1 Introduction

This notebook describes the analysis and interpretation of Methyl-Seq data generated for three developmental timepoints: Stage1 (S1): 0-9.15 hrs Stage2 (S1): 11-12 hrs Stage3 (S1): 24-60 hrs

2 Methylation data processing

2.1 Quality check using FastQC

methyl_seq_raw=Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1.fq.gz # Example: Stage 1, Reads_1
echo "Stage1 raw reads_1:" $methyl_seq_raw
#./software/FastQC/fastqc $methyl_seq_raw Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1.fq.gz 
Stage1 raw reads_1: Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1.fq.gz

2.2 Reads trimming using TrimGalore

#Running on stage1 data
#~/software/TrimGalore-0.6.6/trim_galore --paired  Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1.fq.gz Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_2.fq.gz

echo "Stage1 clean reads: Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1.fq Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_2_val_2.fq"
Stage1 clean reads: Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1.fq Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_2_val_2.fq

2.3 Mapping reads to Phaw5.1 genome

Running bismark_genome_preparation

$phaw_genome=/drives/ssd1/wei/genome/phaw_sambaAsm.scaff_seqs_editedScafNames.fa
~/software/Bismark-0.22.3/bismark_genome_preparation --path_to_bowtie ~/software/bowtie2/bowtie2-2.4.2-sra-linux-x86_64/  
--verbose --bowtie2 $phaw_genome

Running bismark_mapping

#~/software/Bismark-0.22.3/bismark --bowtie2 --path_to_bowtie2 ~/software/bowtie2/bowtie2-2.4.2-sra-linux-x86_64/ 
#--samtools_path ~/software/samtools-1.17 --genome /drives/ssd1/wei/genome -N 1 -L 22 --score_min L,0,-0.6  -1 ./Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1.fq -2 ./Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_2_val_2.fq

echo "Stage1 mapped reads: Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1_bismark_bt2_pe.bam"
Stage1 mapped reads: Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1_bismark_bt2_pe.bam

2.4 Deduplication

#~/software/Bismark-0.22.3/deduplicate_bismark -p --bam Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1_bismark_bt2_pe.bam
echo "Stage1 deduplicated reads: Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1_bismark_bt2_pe.deduplicated.bam"
Stage1 deduplicated reads: Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1_bismark_bt2_pe.deduplicated.bam

2.5 Methylation calling

#~/software/Bismark-0.22.3/bismark_methylation_extractor -p --comprehensive --samtools_path ~/software/samtools-1.17 --bedGraph --scaffolds  --cytosine_report --genome_folder /drives/ssd1/wei/genome/ Stage1_2_EKDL200012840-1a_HHHFMDSXY_L2_1_val_1_bismark_bt2_pe.deduplicated.bam
echo "Covered CpGs - Stage1"
head -5 /drives/ssd1/wei/emseq/map/nocut/S1/S1_CpGsum
Covered CpGs - Stage1
Scaffold_1_HRSCAF_22    9   +   0   0   0
Scaffold_1_HRSCAF_22    10  -   0   0   0
Scaffold_1_HRSCAF_22    17  +   0   0   0
Scaffold_1_HRSCAF_22    18  -   0   0   0
Scaffold_1_HRSCAF_22    24  +   0   0   0

3 Summarise methylation level per stage

3.1 CpG coverage for all CPGs in the genome across stages - Fig S13A

knitr::opts_chunk$set(message=F,warning=F,echo=T)
#Load libraries
library(tidyr)
library(tidyverse)
library(dplyr)
library(ggplot2)
library(reshape2)
library(ggpubr)
library(colortools)
library(Rsubread)
library(tibble)
library(scales)
library(ggbreak) 
library(VennDiagram)
library("RColorBrewer")
library(gridExtra)
library(methylKit)
#Coverage for all CPGs in the genome
covAllCpG_9hr <- read.table("/drives/ssd1/wei/formanuel/S1_CpGsum",header = F) #Covered CpGs stage 0-9:15 hrs
covAllCpG_12hr <- read.table("/drives/ssd1/wei/formanuel/S2_CpGsum",header = F) #Covered CpGs stage 11:12 hrs
covAllCpG_24_60hr <- read.table("/drives/ssd1/wei/formanuel/S3_CpGsum",header = F) #Covered CpGs stage 24:60 hrs

#Merge coverage data
covAllCpG_allStages <- dplyr::bind_rows(list(covAllCpG_9hr,covAllCpG_12hr,covAllCpG_24_60hr), .id = 'stage') %>% 
  mutate(stage = recode(stage, '1' = 'emb_9hr', '2' = 'emb_12hr', '3' = 'emb_24_60hr')) %>%
  mutate(coverage = (V4 + V5))
colnames(covAllCpG_allStages) <- c("stage","Scaffold","pos","strand","mCpG_reads","UnmCpG_reads","methylation_level","coverage")

rm(covAllCpG_9hr,covAllCpG_12hr,covAllCpG_24_60hr)
covAllCpG_allStages %>% group_by(stage) %>% summarise(covMedian = median(coverage),covMean = mean(coverage))

covAllCpG_allStages_distribution <- covAllCpG_allStages  %>% mutate(stage=factor(stage, levels = c('emb_9hr','emb_12hr','emb_24_60hr'))) %>%
  filter(coverage <= 50) %>%
  mutate(coverage=factor(coverage, levels = c(seq(0,50,1)))) %>%
  ggplot(aes(x=coverage,fill=stage)) +  geom_bar(stat='count', position='dodge') +
  scale_x_discrete(labels=c(seq(0,50,10)),breaks =seq(0,50,10) ) + 
  scale_fill_manual(values=c("orange2","mistyrose4","maroon")) +
  scale_y_continuous(expand = c(0,0),labels=unit_format(unit = "M",scale=1e-6))+ ylab("Counts (million)") +xlab("WGBS-seq coverage") +
  #scale_x_discrete(labels= c("0","20","40","60","80","100")) +
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 13,angle =0,vjust = 0.65),
        axis.text.y = element_text(size = 13),legend.position=c(0.8,0.85),
        axis.title = element_text(size = 20),strip.text.x = element_text(size = 12)) 

#tiff("covAllCpG_allStages_distribution.tiff", width = 5, height = 4, units = "in",res = 400,compression = "lzw")
covAllCpG_allStages_distribution 

#dev.off()

3.2 Time-point specific fractional methylation levels - Fig 5A

#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")


#tiff("methyl_level_perStage_allCovCpG.tiff", width = 1.5, height = 3, units = "in",res = 400,compression = "lzw")
meth_allCovCpG_allStages_perStage

#dev.off()

3.3 Methylation level distribution for mCpGs (methylation >= 20) - Fig S13B

mCpg_methylDistribution <- covAllCpG_allStages %>% filter(coverage >= 5, methylation_level >= 20) %>% 
  mutate(stage=factor(stage, levels = c('emb_9hr','emb_12hr','emb_24_60hr'))) %>% 
  ggplot() + 
  geom_histogram(aes(x=methylation_level,y=..count..)) + facet_wrap(~stage) +
  scale_y_continuous(expand = c(0,0),labels=unit_format(unit = "M",scale=1e-6),limits = c(0,1400000))+ 
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 13,angle =30,vjust = 0.65),
        axis.text.y = element_text(size = 13),legend.position=c(0.1,0.85),
        axis.title = element_text(size = 20),strip.text.x = element_text(size = 12)) 

#tiff("mCpg_methylDistribution.tiff", width = 10, height = 4, units = "in",res = 400,compression = "lzw")
mCpg_methylDistribution 
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#dev.off()

3.4 Methylation by genomic feature - Fig 5B and S13D

#Open with summarised methylation data per stage and feature
perFeature_MethStats <- read.table("../wgbs_analysis/wholegenome_te",header = T)
colnames(perFeature_MethStats) <- c("region","5XCov_CpGs","mCpGs","mCpGs_percent","methylation_level","stage","Group")
perFeature_MethStats
#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")
#Plot fraction of methylated CpGs per feature - Fig 13D
mCpG_percent_byFeature <- perFeature_MethStats %>% mutate(stage = recode(stage, 'S1' = '9 hrs', 'S2' = '11-12 hrs', 'S3' = '24_60 hrs')) %>%
  ggplot(aes(x=region , y = mCpGs_percent, fill=stage)) +
  geom_col(position = "dodge",colour = "black", size = 0.1) +
  facet_wrap(~ Group,scales="free_x") +
  scale_fill_manual(values=c("orange2","mistyrose4","maroon")) + scale_y_continuous(expand = c(0,0)) +
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 10,angle =30,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10),legend.position=c(0.1,0.85),legend.background = element_rect(fill='transparent'),
        axis.title = element_text(size = 14),#strip.text.x = element_text(size = 12),
        strip.background = element_blank(),
        strip.text.x = element_blank()) + xlab(NULL) + ylab("Percent of mCpG") 

#Plot fractional methylation per feature - Fig 5B 
mCpG_level_byFeature <- perFeature_MethStats %>% mutate(stage = recode(stage, 'S1' = '9 hrs', 'S2' = '11-12 hrs', 'S3' = '24_60 hrs')) %>%
  ggplot(aes(x=region , y = methylation_level, fill=stage)) +
  geom_col(position = "dodge",colour = "black", size = 0.1) +
  facet_wrap(~ Group,scales="free_x") +
  scale_fill_manual(values=c("orange2","mistyrose4","maroon")) + 
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 10,angle =30,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10),legend.position=c(0.1,0.85),legend.background = element_rect(fill='transparent'),
        axis.title = element_text(size = 14),  strip.background = element_blank(),
        strip.text.x = element_blank()) + xlab(NULL) + ylab("Methylation %") 

#tiff("mCpG_percent_byFeature.tiff", width = 5, height = 3, units = "in",res = 400,compression = "lzw")
mCpG_percent_byFeature #%>% filter(stage =="emb_9hr") %>% filter(methylation_level == "100" ) %>% dim()

#dev.off()

#tiff("mCpG_level_byFeature.tiff", width = 5, height = 3, units = "in",res = 400,compression = "lzw")
mCpG_level_byFeature #%>% filter(stage =="emb_9hr") %>% filter(methylation_level == "100" ) %>% dim()

#dev.off()

3.5 Distribution of covered CpGs across genomic features - Fig S13C

#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")
perGeneFeat_MethStats_allStages <- perFeature_MethStats %>% mutate(stage = recode(stage, 'S1' = '9 hrs', 'S2' = '11-12 hrs', 'S3' = '24-60 hrs')) %>%
  filter(Group == "Gene",region != "Genebody") %>% tibble() %>% 
  ggplot(aes(x = stage, y = `5XCov_CpGs`,fill= region)) + geom_bar(stat='identity', position='fill') +
  scale_y_continuous(expand = c(0,0))+ ylab("Covered CpGs fraction") + xlab(NULL) + scale_fill_brewer(palette = "Set1")+
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 13,angle =30,vjust = 0.65),
        axis.text.y = element_text(size = 13),#legend.position=c(0.1,0.85),
        axis.title = element_text(size = 20),strip.text.x = element_text(size = 12)) 

perTEs_MethStats_allStages <-perFeature_MethStats %>% mutate(stage = recode(stage, 'S1' = '9 hrs', 'S2' = '11-12 hrs', 'S3' = '24-60 hrs')) %>%
  filter(Group == "TE",region != "TE") %>% tibble() %>% 
  ggplot(aes(x = stage, y = `5XCov_CpGs`,fill= region)) + geom_bar(stat='identity', position='fill') +
  scale_y_continuous(expand = c(0,0))+ ylab("Covered CpGs fraction") + xlab(NULL) + scale_fill_brewer(palette = "Dark2")+
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 13,angle =30,vjust = 0.55),
        axis.text.y = element_text(size = 13),#legend.position=c(0.1,0.85),
        axis.title = element_text(size = 20),strip.text.x = element_text(size = 12)) 

#tiff("MethStats_allStages.tiff", width = 6.5, height = 5, units = "in",res = 400,compression = "lzw")
ggarrange(perGeneFeat_MethStats_allStages,perTEs_MethStats_allStages,nrow = 1,ncol = 2)


#dev.off()

4 Dynamics of DNA Methylomes for Early Embryos

I aimed to identify differential methylated CpGs between stages and next interrogate if this changes are prevalent in specific genomic regions. Only included in the analysis CpGs with coverage >=5

4.1 Read the files to a methylRawList object: myobj

methylseq_dir <- "/drives/ssd1/wei/emseq/sum"
methylseq_files <- grep("CpG_report.txt_CG_methykit.txt2$",list.files(methylseq_dir,full.names = T),value=TRUE)

myobj=methRead(as.list(methylseq_files[3:6]),
           sample.id=list("s11h","s11h","s24h","s24h"),
           assembly="phaw51",
           treatment=c(0,0,1,1),
           context="CpG",mincov = 5)
|--------------------------------------------------|
|==================================================|
|--------------------------------------------------|
|==================================================|
|--------------------------------------------------|
|==================================================|
|--------------------------------------------------|
|==================================================|
head(myobj[[4]])
methylRaw object with 6 rows
--------------
data part of methylRaw have 8 columns, expected 7 columns
--------------
sample.id: s24h 
assembly: phaw51 
context: CpG 
resolution: base 

Quality check

getMethylationStats(myobj[[1]],plot=TRUE,both.strands=FALSE)

getMethylationStats(myobj[[2]],plot=TRUE,both.strands=FALSE)

getMethylationStats(myobj[[3]],plot=TRUE,both.strands=FALSE)

getMethylationStats(myobj[[4]],plot=TRUE,both.strands=FALSE)

Merging samples into a single table

meth=methylKit::unite(myobj, destrand=FALSE)
uniting...
clusterSamples(meth, dist="correlation", method="ward", plot=TRUE)
The "ward" method has been renamed to "ward.D"; note new "ward.D2"

Call:
hclust(d = d, method = HCLUST.METHODS[hclust.method])

Cluster method   : ward.D 
Distance         : pearson 
Number of objects: 4 

pc=PCASamples(meth,obj.return = TRUE, adj.lim=c(1,1))

4.2 Filtering CpGs based on variation

Calculate per CpG variation

pm=percMethylation(meth) # get percent methylation matrix
mds=matrixStats::rowSds(pm) # calculate standard deviation of CpGs
head(meth[mds>5,])
methylBase object with 6 rows
--------------
--------------
sample.ids: s11h s11h s24h s24h 
destranded FALSE 
assembly: phaw51 
context: CpG 
treament: 0 0 1 1 
resolution: base 

Histogram of CpG variation

hist(mds,col="gainsboro",xlab="Std. dev. per CpG",breaks = 100)

Keep CpGs with standard deviations larger than 2% - Cluster samples

meth <- meth[mds>2,]
print(paste0("# of CpGs forn downstream analysis: ",nrow(meth)))
[1] "# of CpGs forn downstream analysis: 3418434"

4.3 Extracting differential methylated CpGs. 9hrs to 11 hrs transtion

Samples per conditions were pulled and Fisher’s exact test was applied.

getSampleID(meth)
[1] "s11h" "s11h" "s24h" "s24h"
pooled.meth=pool(meth,sample.ids=c("s11h","s24h"))
dm.pooledf=calculateDiffMeth(pooled.meth)
two groups detected:
 will calculate methylation difference as the difference of
treatment (group: 1) - control (group: 0)

 NOTE: performing 'fast.fisher' instead of 'F' for two groups testing.

Get differentially methylated bases/regions

# All sites
all.diff=getMethylDiff(dm.pooledf,difference=5,qvalue=0.05,type="all")

# get hyper-methylated
hyper=getMethylDiff(dm.pooledf,difference=5,qvalue=0.05,type="hyper")

# get hypo-methylated
hypo=getMethylDiff(dm.pooledf,difference=5,qvalue=0.05,type="hypo")

4.4 Differentially methylated Regions

Tile the genome with windows of 1000bp length and 1000 bp step-size

5 Gene body (+-2kb) methylation analysis - Fig 5C

Process and summarise methylation per window across genes Each gene was split into 100 windows, CpGs were mapped to each window and the average methylation per window was estimated. The same process was performed on 2kb upstream and downstream regions, which were split into 20 windows

Summarising gene body methylation per stage

tiles=tileMethylCounts(myobj,win.size=1000,step.size=1000)
#head(tiles[[1]],3)

Combine into single object

meth_byRegion=methylKit::unite(tiles, destrand=FALSE)
uniting...

Extracting differential methylated regions. 11hrs to 24hrs transtion Samples per conditions were pulled and Fisher’s exact test was applied.

getSampleID(meth_byRegion)
[1] "s11h" "s11h" "s24h" "s24h"
pooled.methRegion=pool(meth_byRegion,sample.ids=c("s11h","s9h"))
dm.pooledf_byRegion=calculateDiffMeth(pooled.methRegion)
two groups detected:
 will calculate methylation difference as the difference of
treatment (group: 1) - control (group: 0)

 NOTE: performing 'fast.fisher' instead of 'F' for two groups testing.
# All sites
all.diff=getMethylDiff(dm.pooledf_byRegion,difference=5,qvalue=0.05,type="all")
print(paste0("All diffMeth:",nrow(all.diff)))
[1] "All diffMeth:37748"
# get hyper-methylated
hyper=getMethylDiff(dm.pooledf_byRegion,difference=5,qvalue=0.05,type="hyper")
print(paste0("All diffMeth:",nrow(hyper)))
[1] "All diffMeth:10546"
# get hypo-methylated
hypo=getMethylDiff(dm.pooledf_byRegion,difference=5,qvalue=0.05,type="hypo")
print(paste0("All diffMeth:",nrow(hypo)))
[1] "All diffMeth:27202"

Intersect with genic and TE elements

#Call window-based methylation files per stage
s1_genebody_w100 <- read.table("/drives/ssd1/wei/genome/genebody/nostrand/S1_genebody_win100_5_sum", header = F, stringsAsFactors = F)
colnames(s1_genebody_w100) <- c("gene_id","window","cpg_count","methylation")
s2_genebody_w100 <- read.table("/drives/ssd1/wei/genome/genebody/nostrand/S2_genebody_win100_5_sum", header = F, stringsAsFactors = F)
colnames(s2_genebody_w100) <- c("gene_id","window","cpg_count","methylation")
s3_genebody_w100 <- read.table("/drives/ssd1/wei/genome/genebody/nostrand/S3_genebody_win100_5_sum", header = F, stringsAsFactors = F)
colnames(s3_genebody_w100) <- c("gene_id","window","cpg_count","methylation")

# Summarise files, estimating window-based average methylation across genes
s1_genebody_w100 <- s1_genebody_w100 %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s1_genebody_w100 <- s1_genebody_w100[,c("gene_id",paste0("w",seq(1:100)))]

s2_genebody_w100 <- s2_genebody_w100  %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s2_genebody_w100 <- s2_genebody_w100[,c("gene_id",paste0("w",seq(1:100)))]

s3_genebody_w100 <- s3_genebody_w100  %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s3_genebody_w100 <- s3_genebody_w100[,c("gene_id",paste0("w",seq(1:100)))]

# Final data
s1_genebody_w100 <- s1_genebody_w100 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s2_genebody_w100 <- s2_genebody_w100 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s3_genebody_w100 <- s3_genebody_w100 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s1_genebody_w100
s2_genebody_w100
s3_genebody_w100

Summarizing 2kb downstream gene region per stage

#Call window-based methylation files per stage
s1_down_20 <- read.table("/drives/ssd1/wei/genome/down/nostrand/S1_down2kb_win20_5_sum", header = F, stringsAsFactors = F)
colnames(s1_down_20) <- c("gene_id","window","cpg_count","methylation")
s2_down_20 <- read.table("/drives/ssd1/wei/genome/down/nostrand/S2_down2kb_win20_5_sum", header = F, stringsAsFactors = F)
colnames(s2_down_20) <- c("gene_id","window","cpg_count","methylation")
s3_down_20 <- read.table("/drives/ssd1/wei/genome/down/nostrand/S3_down2kb_win20_5_sum", header = F, stringsAsFactors = F)
colnames(s3_down_20) <- c("gene_id","window","cpg_count","methylation")

# Summarise files, estimating window-based average methylation across genes
s1_down_20 <- s1_down_20 %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s1_down_20 <- s1_down_20[,c("gene_id",paste0("w",seq(1:20)))]

s2_down_20 <- s2_down_20  %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s2_down_20 <- s2_down_20[,c("gene_id",paste0("w",seq(1:20)))]

s3_down_20 <- s3_down_20  %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s3_down_20 <- s3_down_20[,c("gene_id",paste0("w",seq(1:20)))]

# Final data
s1_down_20 <- s1_down_20 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s2_down_20 <- s2_down_20 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s3_down_20 <- s3_down_20 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s1_down_20
s2_down_20
s3_down_20

Summarizing 2kb upstream gene region per stage

#Call window-based methylation files per stage
s1_up_20 <- read.table("/drives/ssd1/wei/genome/up/nostrand/S1_up2kb_win20_5_sum", header = F, stringsAsFactors = F)
colnames(s1_up_20) <- c("gene_id","window","cpg_count","methylation")
s2_up_20 <- read.table("/drives/ssd1/wei/genome/up/nostrand/S2_up2kb_win20_5_sum", header = F, stringsAsFactors = F)
colnames(s2_up_20) <- c("gene_id","window","cpg_count","methylation")
s3_up_20 <- read.table("/drives/ssd1/wei/genome/up/nostrand/S3_up2kb_win20_5_sum", header = F, stringsAsFactors = F)
colnames(s3_up_20) <- c("gene_id","window","cpg_count","methylation")

# Summarise files, estimating window-based average methylation across genes
s1_up_20 <- s1_up_20 %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s1_up_20 <- s1_up_20[,c("gene_id",paste0("w",seq(1:20)))]

s2_up_20 <- s2_up_20  %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s2_up_20 <- s2_up_20[,c("gene_id",paste0("w",seq(1:20)))]

s3_up_20 <- s3_up_20  %>%
  mutate(window=paste0("w",window)) %>% pivot_wider(- cpg_count,names_from = window,values_from = methylation) 
s3_up_20 <- s3_up_20[,c("gene_id",paste0("w",seq(1:20)))]

# Final data
s1_up_20 <- s1_up_20 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s2_up_20 <- s2_up_20 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s3_up_20 <- s3_up_20 %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)
s1_up_20
s2_up_20
s3_up_20

Merge upstream, gene_body and downstream average methylation data

up_gene_down_meth <- rbind(
cbind(s1_up_20,s1_genebody_w100,s1_down_20),
cbind(s2_up_20,s2_genebody_w100,s2_down_20),
cbind(s3_up_20,s3_genebody_w100,s3_down_20)) #%>% mutate(stage= c("S1","S2","S3"))
colnames(up_gene_down_meth) <- paste0("w",seq(1:140))
up_gene_down_meth <- up_gene_down_meth %>% dplyr::mutate(stage= c("S1","S2","S3")) %>% pivot_longer(-stage)
up_gene_down_meth

Plot

#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")
geneBody_upDown_meth_plot <-up_gene_down_meth %>% 
  mutate(stage=factor(stage, levels= c("S1","S2","S3")),
         name=factor(name,levels =paste0("w",seq(1:140)))) %>%
  ggplot(aes(y=value ,x=name, group=stage,color=stage)) + geom_line(size=0.8)  +
  xlab("") +  ylab("Methylation (%)") +
  ggtitle("") +
  scale_x_discrete(breaks = c('w8','w20','w70','w120','w135'), 
                     labels=c("Upstream","TSS","Gene body","TES","Downstream")) +
  scale_color_manual(values = c("orange2","mistyrose4","maroon"),
                     breaks = c("S1","S2","S3"),
                     labels = c("0-9 hrs","11-12 hrs","24-60 hrs")) + theme_bw() +
  theme(panel.grid.major = element_line(colour=NA),
        panel.background = element_rect(fill= "transparent", colour=NA),
        plot.background = element_rect(fill = "transparent",colour = NA),
        panel.grid.minor = element_blank(),
        legend.position = c(0.87,0.65),
        legend.title = element_blank(),
        legend.key.size = unit(15,"pt"),
        legend.text=element_text(size=8),
        axis.text.y = element_text(size = 10),axis.text.x = element_text(size = 10,vjust = 1.15,angle=30,hjus=1.2),
        axis.title.x = element_text(size = 14),axis.title.y = element_text(size = 14))

#tiff("geneBody_upDown_meth.tiff", width = 4, height = 2.5, units = "in",res = 400,compression = "lzw")
geneBody_upDown_meth_plot

#dev.off()

6 Exon-intron methylation level - Fig 5D

Each exon was split in 30 windows, while each intron was split in 80 windows. For each windows, the average CpG methylation was estimated. The graph represent the average methylation per window across genes, using only the first four exons and introns.

Exon methylation

#Call window-based methylation files per stage
s1_exon_30 <- read.table("/drives/ssd1/wei/genome/exon/nostrand/S1_exon_modify_win30_5_sum", header = F, stringsAsFactors = F)
colnames(s1_exon_30) <- c("gene_id","exon_n","window","cpg_count","methylation")
s2_exon_30 <- read.table("/drives/ssd1/wei/genome/exon/nostrand/S2_exon_modify_win30_5_sum", header = F, stringsAsFactors = F)
colnames(s2_exon_30) <- c("gene_id","exon_n","window","cpg_count","methylation")
s3_exon_30 <- read.table("/drives/ssd1/wei/genome/exon/nostrand/S3_exon_modify_win30_5_sum", header = F, stringsAsFactors = F)
colnames(s3_exon_30) <- c("gene_id","exon_n","window","cpg_count","methylation")
s1_exon_30 %>% head()
#Summarised intron methylation - Stage1
exon_methy_list_s1 = list()
for (i in 1:4) { # Only extract data for first 4 introns
  temp_df <- s1_exon_30 %>% mutate(window=paste0("w",window)) %>% filter(exon_n == i) %>% 
    pivot_wider(- cpg_count,names_from = window,values_from = methylation) %>% select(-exon_n)
  temp_df <- temp_df[,c("gene_id",paste0("w",seq(1:30)))]
  temp_df <- temp_df %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)

exon_methy_list_s1[[i]] <- temp_df
}

#Summarised intron methylation - Stage2
exon_methy_list_s2 = list()
for (i in 1:4) { # Only extract data for first 4 introns
  temp_df <- s2_exon_30 %>% mutate(window=paste0("w",window)) %>% filter(exon_n == i) %>% 
    pivot_wider(- cpg_count,names_from = window,values_from = methylation) %>% select(-exon_n)
  temp_df <- temp_df[,c("gene_id",paste0("w",seq(1:30)))]
  temp_df <- temp_df %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)

exon_methy_list_s2[[i]] <- temp_df
}

#Summarised intron methylation - Stage2
exon_methy_list_s3 = list()
for (i in 1:4) { # Only extract data for first 4 introns
  temp_df <- s3_exon_30 %>% mutate(window=paste0("w",window)) %>% filter(exon_n == i) %>% 
    pivot_wider(- cpg_count,names_from = window,values_from = methylation) %>% select(-exon_n)
  temp_df <- temp_df[,c("gene_id",paste0("w",seq(1:30)))]
  temp_df <- temp_df %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)

exon_methy_list_s3[[i]] <- temp_df
}
exon_methy_list_s1
[[1]]

[[2]]

[[3]]

[[4]]
NA

Intron methylation

#Call window-based methylation files per stage
s1_intron_80 <- read.table("/drives/ssd1/wei/genome/intron/nostrand/S1_intron_modify_win80_5_sum", header = F, stringsAsFactors = F)
colnames(s1_intron_80) <- c("gene_id","intron_n","window","cpg_count","methylation")
s2_intron_80 <- read.table("/drives/ssd1/wei/genome/intron/nostrand/S2_intron_modify_win80_5_sum", header = F, stringsAsFactors = F)
colnames(s2_intron_80) <- c("gene_id","intron_n","window","cpg_count","methylation")
s3_intron_80 <- read.table("/drives/ssd1/wei/genome/intron/nostrand/S3_intron_modify_win80_5_sum", header = F, stringsAsFactors = F)
colnames(s3_intron_80) <- c("gene_id","intron_n","window","cpg_count","methylation")
s1_intron_80 %>% head()
#Summarised intron methylation - Stage1
intron_methy_list_s1 = list()
for (i in 1:4) { # Only extract data for first 4 introns
  temp_df <- s1_intron_80 %>% mutate(window=paste0("w",window)) %>% filter(intron_n == i) %>% 
    pivot_wider(- cpg_count,names_from = window,values_from = methylation) %>% select(-intron_n)
  temp_df <- temp_df[,c("gene_id",paste0("w",seq(1:80)))]
  temp_df <- temp_df %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)

intron_methy_list_s1[[i]] <- temp_df
}

#Summarised intron methylation - Stage2
intron_methy_list_s2 = list()
for (i in 1:4) { # Only extract data for first 4 introns
  temp_df <- s2_intron_80 %>% mutate(window=paste0("w",window)) %>% filter(intron_n == i) %>% 
    pivot_wider(- cpg_count,names_from = window,values_from = methylation) %>% select(-intron_n)
  temp_df <- temp_df[,c("gene_id",paste0("w",seq(1:80)))]
  temp_df <- temp_df %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)

intron_methy_list_s2[[i]] <- temp_df
}

#Summarised intron methylation - Stage2
intron_methy_list_s3 = list()
for (i in 1:4) { # Only extract data for first 4 introns
  temp_df <- s3_intron_80 %>% mutate(window=paste0("w",window)) %>% filter(intron_n == i) %>% 
    pivot_wider(- cpg_count,names_from = window,values_from = methylation) %>% select(-intron_n)
  temp_df <- temp_df[,c("gene_id",paste0("w",seq(1:80)))]
  temp_df <- temp_df %>% select(-gene_id) %>% summarise_all(mean,na.rm = TRUE)

intron_methy_list_s3[[i]] <- temp_df
}
intron_methy_list_s1
[[1]]

[[2]]

[[3]]

[[4]]
NA

Merge exon and intron methylation data

exon_intron_meth <- rbind(cbind(exon_methy_list_s1[[1]],intron_methy_list_s1[[1]],exon_methy_list_s1[[2]],intron_methy_list_s1[[2]],
                          exon_methy_list_s1[3],intron_methy_list_s1[[3]],exon_methy_list_s1[[4]],intron_methy_list_s1[[4]]),
                    cbind(exon_methy_list_s2[[1]],intron_methy_list_s2[[1]],exon_methy_list_s2[[2]],intron_methy_list_s2[[2]],
                          exon_methy_list_s2[3],intron_methy_list_s2[[3]],exon_methy_list_s2[[4]],intron_methy_list_s2[[4]]),
                    cbind(exon_methy_list_s3[[1]],intron_methy_list_s3[[1]],exon_methy_list_s3[[2]],intron_methy_list_s3[[2]],
                          exon_methy_list_s3[3],intron_methy_list_s3[[3]],exon_methy_list_s3[[4]],intron_methy_list_s3[[4]]))

colnames(exon_intron_meth) <- paste0("w",seq(1:440))
exon_intron_meth <- exon_intron_meth %>% dplyr::mutate(stage= c("S1","S2","S3")) %>% pivot_longer(-stage)
exon_intron_meth
#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")
exonIntron_meth_plot <- exon_intron_meth %>% 
  mutate(stage=factor(stage, levels= c("S1","S2","S3")),
         name=factor(name,levels =paste0("w",seq(1:440)))) %>%
  ggplot(aes(y=value ,x=name, group=stage,color=stage)) + geom_line(size=0.8)  +
  xlab("") +  ylab("Methylation (%)") + ggtitle(NULL) +
  scale_x_discrete(breaks = paste0('w',c(1,15,30,70,110,125,140,180,220,235,250,290,330,345,360,400,440)), 
                     labels=c(" ","Exon1"," ","Intron1"," ","Exon2"," ","Intron2"," ","Exon3"," ","Intron3"," ","Exon4"," ","Intron4"," ")) +
  scale_color_manual(values = c("orange2","mistyrose4","maroon"),
                     breaks = c("S1","S2","S3"),
                     labels = c("0-9 hrs","11-12 hrs","24-60 hrs")) + theme_bw() +
  theme(panel.grid.major = element_line(colour=NA),
        panel.background = element_rect(fill= "transparent", colour=NA),
        plot.background = element_rect(fill = "transparent",colour = NA),
        panel.grid.minor = element_blank(), legend.position = c(0.87,0.65), legend.title = element_blank(),
        legend.key.size = unit(12,"pt"), legend.text=element_text(size=7),
        axis.text.y = element_text(size = 10),axis.text.x = element_text(size = 8,vjust = 0.5),
        axis.title.x = element_text(size = 14),axis.title.y = element_text(size = 14))

#tiff("exonIntron_meth.tiff", width = 4, height = 2, units = "in",res = 400,compression = "lzw")
exonIntron_meth_plot

#dev.off()

7 Analysis of covered Cpgs, %of mCpg and methylation level for whole gene length and first 2500 bp

Load data

#CpGs covered along full gene body - Number and methylation average per gene
s1_covCpG_count <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s1_covCpG_count",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')
s2_covCpG_count <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s2_covCpG_count",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')
s3_covCpG_count <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s3_covCpG_count",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')

#mCpGs along full gene body - Number and methylation average per gene

s1_mCpG_count <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s1_mCpG_count",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')
s2_mCpG_count <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s2_mCpG_count",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')
s3_mCpG_count<-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s3_mCpG_count",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')

#CpGs covered along 5' 2500 bp of each gene - Number and methylation average per gene
s1_covCpG_count_first2500bp <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s1_covCpG_count_first2500bp",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')
s2_covCpG_count_first2500bp <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s2_covCpG_count_first2500bp",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')
s3_covCpG_count_first2500bp <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s3_covCpG_count_first2500bp",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')

#mCpGs along 5' 2500 bp of each gene - Number and methylation average per gene

s1_mCpG_count_first2500bp <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s1_mCpG_count_first2500bp",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')
s2_mCpG_count_first2500bp <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s2_mCpG_count_first2500bp",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')
s3_mCpG_count_first2500bp <-  read.table("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/s3_mCpG_count_first2500bp",header = F,sep= "\t", stringsAsFactors = F,na.strings = '.')

Merge and summarise whole gene body methylation data

geneBody_full_methData <- dplyr::bind_rows(list(s1_covCpG_count,s2_covCpG_count,s3_covCpG_count,s1_mCpG_count,s2_mCpG_count,s3_mCpG_count), .id = 'class') %>%
  mutate(class = recode(class, '1' = 'Cov9hrs', '2' = 'Cov12hrs', '3' = 'Cov24hrs',
                        '4' = 'mCpG9hrs', '5' = 'mCpG12hrs', '6' = 'mCpG24hrs'))
colnames(geneBody_full_methData) <- c("class","gene","group","strand","CpG_N","methylation")
geneBody_full_methData %>% head()

Estimate percentage of gene body methylated CpGs (mCpG) - Fig 5E left

knitr::opts_chunk$set(message=F,warning=F,echo=T)
#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")
geneBody_mcpg_perc <- geneBody_full_methData %>% select(-c(group,strand)) %>%
  pivot_wider(names_from=class,values_from= c(CpG_N,methylation)) %>% 
  mutate(mCpG_perc9hr= (CpG_N_mCpG9hrs/CpG_N_Cov9hrs)*100,
         mCpG_perc12hr= (CpG_N_mCpG12hrs/CpG_N_Cov12hrs)*100,
         mCpG_perc24hr= (CpG_N_mCpG24hrs/CpG_N_Cov24hrs)*100) %>% select(gene,mCpG_perc9hr,mCpG_perc12hr,mCpG_perc24hr) %>%
  melt(id.vars="gene",value.name = "mCpG_perc") %>% 
  ggplot(aes(x=variable,y=mCpG_perc,fill=variable)) + geom_boxplot(outlier.colour = "grey",size=0.4) +
  scale_x_discrete(labels= c("9 hrs","11-12 hrs","24-60 hrs")) +
  scale_y_break(c(40, 95), scales = 0.1, ticklabels=c(95, 100)) + ylab("Gene body mCpG %") +
  scale_fill_manual(values=c("orange2","mistyrose4","maroon")) + 
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 10,angle =30,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10),legend.position="none",
        axis.text.x.top = element_blank(),
        axis.ticks.x.top = element_blank(),
        axis.line.x.top = element_blank(),
        axis.title = element_text(size = 14),strip.text.x = element_text(size = 12)) + xlab(NULL) + ylab(NULL)

suppressWarnings(grid.arrange(geneBody_mcpg_perc))


#tiff("geneBody_mcpg_perc.tiff", width = 1.5, height = 3, units = "in",res = 400,compression = "lzw")
#geneBody_mcpg_per
#dev.off()

Estimate gene body methylation level - Fig 5F left

#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")

geneBody_methLevel_all <- geneBody_full_methData %>% select(-c(group,strand)) %>% #sample_n(6000) %>%
  pivot_wider(names_from=class,values_from= c(CpG_N,methylation)) %>% 
  select(gene,methylation_Cov9hrs:methylation_Cov24hrs) %>%
  melt(id.vars="gene",value.name = "Methylation") %>% #tibble() %>% 
  ggplot(aes(x=variable,y=as.numeric(Methylation),fill=variable)) + geom_boxplot() +
  scale_x_discrete(labels= c("9 hrs","11-12 hrs","24-60 hrs")) +  
  scale_y_break(c(30, 95), scales = 0.1, ticklabels=c(95, 100)) + #scale_x_break(c(40,90), scales=2) +
  scale_fill_manual(values=c("orange2","mistyrose4","maroon")) + 
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 10,angle =30,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10),legend.position="none",
        axis.title = element_text(size = 14),strip.text.x = element_text(size = 12),
        axis.text.x.top = element_blank(),
        axis.ticks.x.top = element_blank(),
        axis.line.x.top = element_blank()) + xlab(NULL) + ylab("Gene body methylation %")

suppressWarnings(grid.arrange(geneBody_methLevel_all))

#tiff("geneBody_methLevel_all.tiff", width = 1.5, height = 3, units = "in",res = 400,compression = "lzw")
#geneBody_methLevel_all
#dev.off()

Merge and summarise gene body (first 2500 bp) methylation data

geneBody_up2500_methData <- dplyr::bind_rows(list(s1_covCpG_count_first2500bp,s2_covCpG_count_first2500bp,s3_covCpG_count_first2500bp,
                                                  s1_mCpG_count_first2500bp,s2_mCpG_count_first2500bp,s3_mCpG_count_first2500bp), .id = 'class') %>% 
  mutate(class = recode(class, '1' = 'Cov9hrs', '2' = 'Cov12hrs', '3' = 'Cov24hrs',
                        '4' = 'mCpG9hrs', '5' = 'mCpG12hrs', '6' = 'mCpG24hrs'))
colnames(geneBody_up2500_methData) <- c("class","gene","group","strand","CpG_N","methylation")
geneBody_up2500_methData %>% head()

Estimate percentage of gene body (first 2500 bp) methylated CpGs (mCpG) - Fig 5E right

#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")

geneBody2500_mcpg_perc <- geneBody_up2500_methData %>%  select(-c(group,strand)) %>%
  pivot_wider(names_from=class,values_from= c(CpG_N,methylation)) %>% 
  mutate(mCpG_perc9hr= (CpG_N_mCpG9hrs/CpG_N_Cov9hrs)*100,
         mCpG_perc12hr= (CpG_N_mCpG12hrs/CpG_N_Cov12hrs)*100,
         mCpG_perc24hr= (CpG_N_mCpG24hrs/CpG_N_Cov24hrs)*100) %>% select(gene,mCpG_perc9hr,mCpG_perc12hr,mCpG_perc24hr) %>%
  melt(id.vars="gene",value.name = "mCpG_perc") %>% 
  ggplot(aes(x=variable,y=mCpG_perc,fill=variable)) + geom_boxplot(outlier.colour = "grey",size=0.4) +
  scale_x_discrete(labels= c("9 hrs","11-12 hrs","24-60 hrs")) +
  scale_y_break(c(40, 95), scales = 0.1, ticklabels=c(95, 100)) + #scale_x_break(c(40,90), scales=2) +
  scale_fill_manual(values=c("orange2","mistyrose4","maroon")) + 
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 10,angle =30,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10),legend.position="none",
        axis.text.x.top = element_blank(),
        axis.ticks.x.top = element_blank(),
        axis.line.x.top = element_blank(),
        axis.title = element_text(size = 14),strip.text.x = element_text(size = 12)) + xlab(NULL) + ylab(NULL)

suppressWarnings(grid.arrange(geneBody2500_mcpg_perc))


#tiff("geneBody2500_mcpg_perc.tiff", width = 1.5, height = 3, units = "in",res = 400,compression = "lzw")
#geneBody2500_mcpg_perc
#dev.off()

Estimate gene body (first 2500 bp) methylation level - Fig 5F right

#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")

geneBody2500_methLevel_all <- geneBody_up2500_methData %>% select(-c(group,strand)) %>% #sample_n(6000) %>%
  pivot_wider(names_from=class,values_from= c(CpG_N,methylation)) %>% 
  select(gene,methylation_Cov9hrs:methylation_Cov24hrs) %>%
  melt(id.vars="gene",value.name = "Methylation") %>% #tibble() %>% 
  ggplot(aes(x=variable,y=as.numeric(Methylation),fill=variable)) + geom_boxplot() +
  scale_x_discrete(labels= c("9 hrs","11-12 hrs","24-60 hrs")) +  
  scale_y_break(c(30, 95), scales = 0.1, ticklabels=c(95, 100)) + #scale_x_break(c(40,90), scales=2) +
  scale_fill_manual(values=c("orange2","mistyrose4","maroon")) + 
  theme(legend.title=element_blank(),axis.text.x = element_text(size = 10,angle =30,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10),legend.position="none",
        axis.title = element_text(size = 14),strip.text.x = element_text(size = 12),
        axis.text.x.top = element_blank(),
        axis.ticks.x.top = element_blank(),
        axis.line.x.top = element_blank()) + xlab(NULL) +  ylab("Gene body methylation %")

suppressWarnings(grid.arrange(geneBody2500_methLevel_all))


#tiff("geneBody2500_methLevel_all.tiff", width = 1.5, height = 3, units = "in",res = 400,compression = "lzw")
#geneBody2500_methLevel_all
#dev.off()

Covered CpGs per gene - Fig S13E

#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")
geneBody_Cov_N_all_density <- geneBody_full_methData %>% select(-c(group,strand)) %>% 
  filter(grepl('Cov',class)) %>% mutate(class=gsub("Cov","",class)) %>% mutate(class= factor(class,levels = c("9hrs","12hrs","24hrs"))) %>%
  ggplot(aes(x=as.numeric(CpG_N),fill= `class`)) + geom_density(alpha=0.5) + xlim(NA,500) + scale_y_continuous(expand = c(0,0)) +
  scale_fill_manual(values=c("orange2","mistyrose4","maroon"),labels= c("9 hrs","11-12 hrs","24-60 hrs")) +
  geom_vline(aes(xintercept = 10), color="chocolate4", linetype="dashed", size=0.5) + theme_bw() +
  theme(legend.title=element_blank(),legend.background = element_rect(fill='transparent'),
        axis.text.x = element_text(size = 10,angle =0,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10),legend.position=c(0.85,0.8),
        axis.title = element_text(size = 14),strip.text.x = element_text(size = 12),
        axis.text.x.top = element_blank(),
        axis.ticks.x.top = element_blank(),
        axis.line.x.top = element_blank()) + ylab("Density") + xlab("Covered CpGs per gene")

#tiff("geneBody_Cov_N_all_density.tiff", width = 3.5, height = 3, units = "in",res = 400,compression = "lzw")
geneBody_Cov_N_all_density
Warning: Removed 39023 rows containing non-finite values (stat_density).

#dev.off()

Pattern of gene methylation per stage - Fig 5G

#setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")
geneBody_methLevel_all_density <- geneBody_full_methData %>% select(-c(group,strand)) %>% 
  filter(grepl('Cov',class)) %>% mutate(class=gsub("Cov","",class)) %>% mutate(class= factor(class,levels = c("9hrs","12hrs","24hrs"))) %>%
  ggplot(aes(x=as.numeric(methylation),fill= `class`)) + geom_density(alpha=0.5) +
  scale_x_continuous(trans = log10_trans(),
                     breaks = c(0,0.01,0.1,1,3,10,100),
                     labels = label_number(accuracy = 1)) + scale_y_continuous(expand = c(0,0)) +
  scale_fill_manual(values=c("orange2","mistyrose4","maroon"),labels= c("9 hrs","11-12 hrs","24-60 hrs")) +
  geom_vline(aes(xintercept = 3), color="chocolate4", linetype="dashed", size=0.5) + theme_bw() +
  theme(legend.title=element_blank(),legend.background = element_rect(fill='transparent'),
        axis.text.x = element_text(size = 10,angle =0,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10),legend.position=c(0.15,0.8),
        axis.title = element_text(size = 14),strip.text.x = element_text(size = 12),
        axis.text.x.top = element_blank(),
        axis.ticks.x.top = element_blank(),
        axis.line.x.top = element_blank()) + ylab("Density") + xlab("Gene methylation %")


#tiff("geneBody_methLevel_all_density.tiff", width = 3.5, height = 3, units = "in",res = 400,compression = "lzw")
geneBody_methLevel_all_density
Warning: Transformation introduced infinite values in continuous x-axis
Warning: Removed 4791 rows containing non-finite values (stat_density).

#dev.off()

8 Identify and quantify methylated genes per stage - Fig 5H

setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")

methylatedGenes_9hrs <- geneBody_full_methData %>% filter(class == "Cov9hrs" & CpG_N >= 5 & methylation >= 3) %>% pull(gene) 
methylatedGenes_12hrs <- geneBody_full_methData %>% filter(class == "Cov12hrs" & CpG_N >= 5 & methylation >= 3) %>% pull(gene)
methylatedGenes_24hrs <- geneBody_full_methData %>% filter(class == "Cov24hrs" & CpG_N >= 5 & methylation >= 3) %>% pull(gene)

Reduce(intersect,list(methylatedGenes_9hrs,methylatedGenes_12hrs,methylatedGenes_24hrs)) %>% unique() %>% length()

#Plot venn diagram intersecting methylated genes among stages

venn.diagram(
  x = list(methylatedGenes_9hrs,methylatedGenes_12hrs,methylatedGenes_24hrs),
  category.names = c("9 hrs" , "11-12 hrs","24-60 hrs"),
  filename = 'methylatedGenes_overlapp.tiff',
  height = 4, width = 4, resolution = 300, imagetype = "tiff", 
  units = "in", compression = "lzw", fill= c("orange2","mistyrose4","maroon" ),
  output=T, scaled=T,print.mode=c("raw","percent"))
  

Visualise venn diagrame in the notebook

plt = venn.diagram(
  x = list(methylatedGenes_9hrs,methylatedGenes_12hrs,methylatedGenes_24hrs),
  category.names = c("9 hrs" , "11-12 hrs","24-60 hrs"),
  filename = NULL,
  height = 4, width = 4, resolution = 300, imagetype = "tiff", 
  units = "in", compression = "lzw", fill= c("orange2","mistyrose4","maroon" ),
  output=T, scaled=T,print.mode=c("raw","percent"))
grid.newpage()
grid::grid.draw(plt)

9 Relationship between gene methylation and expression levels

For each methylome dataset (0-9,11-12 and 24-60 hrs) we analysed the expression levels in three subsequent embryonic stages. Expression was categorised as absent (TPM = 0), low(TPM <=1), moderate (TPM <=5) and high (TPM >=5)

Merge Methyl and expression data

embryo_exonCounts_polyA_tpm <- read.table("/drives/ssd1/manuel/phaw/2022_analysis/mzt_analysis/embryo_exonCounts_polyA_tpm.txt",header = T,stringsAsFactors = F)
colnames(embryo_exonCounts_polyA_tpm) <- c("gene_id","0-9hrs","11hrs","12hrs","14hrs","16hrs","20hrs","24hrs","24-60hrs")

embryo_Exp_Methyl_data <- merge(embryo_exonCounts_polyA_tpm,
geneBody_full_methData %>% select(-c(group,strand)) %>% 
  filter(grepl('Cov',class)) %>% mutate(class=gsub("Cov","",class)) %>% 
  mutate(class= factor(class,levels = c("9hrs","12hrs","24hrs"))) %>% 
  pivot_wider(names_from=class,values_from= c(CpG_N,methylation)),by.x = "gene_id",by.y = "gene")

embryo_Exp_Methyl_data

Gene expression at 11, 12 and 13-14 hrs embryos based on methylation from 0-9:15 hrs embryos - Fig 5I, left

get_my_colors <- colorRampPalette(brewer.pal(6, "Dark2"))
mycolors <- get_my_colors(8)

# Correlate 9hrs methylation with all expression timepoints - Boxplots
ExpMethyl_cor_9hrs <- embryo_Exp_Methyl_data %>% select(-c(`CpG_N_9hrs`:`CpG_N_24hrs`,`methylation_12hrs`,`methylation_24hrs`)) %>% 
  pivot_longer(cols = -c(gene_id,methylation_9hrs),names_to = "exp_stage",values_to="exp_count") %>% 
  mutate(exp_stage=factor(exp_stage,levels = c("gene_id","0-9hrs","11hrs","12hrs","14hrs","16hrs","20hrs","24hrs","24-60hrs"))) %>%
  mutate(exp_cat= ifelse(exp_count == 0, "0",
                         ifelse(between(exp_count,0,1),"≤ 1",
                                ifelse(between(exp_count,1,5),"≤ 5","≥ 5")))) %>% 
  filter(exp_stage %in% c("11hrs","12hrs","14hrs")) %>%  # filter(gene_id %in% methylatedGenes_9hrs) %>%
  mutate(exp_cat=factor(exp_cat,levels = c("0","≤ 1","≤ 5","≥ 5"))) %>%
  ggplot(aes(fill=exp_stage,x=exp_cat,y=methylation_9hrs)) + geom_boxplot(outlier.colour = "grey",outlier.size = 0.4,alpha=0.6)+
  ylim(NA,20) + # to print in notebook
  #scale_y_break(c(20, 95), scales = 0.01, ticklabels=c(95, 100)) + # to save figure
  scale_fill_manual(values=c("firebrick3","darkslategray","dodgerblue")) + 
  geom_hline(aes(yintercept = 3), color="chocolate4", linetype="dashed", size=0.5) +
  geom_hline(aes(yintercept = 3), color="chocolate4", linetype="dashed", size=0.5) +
  theme(legend.title=element_blank(),legend.key.size = unit(0.5, 'cm'),legend.text = element_text(size=6),
        legend.position="top",legend.justification="right",legend.margin=margin(0,0,0,0),#legend.box.margin=margin(-20,-100,-10,-10),
        axis.text.x = element_text(size = 10,angle =0,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10), axis.title = element_text(size = 14),strip.text.x = element_text(size = 12),
        axis.text.x.top = element_blank(),axis.ticks.x.top = element_blank(),axis.line.x.top = element_blank()) + 
  ylab("Gene methylation % - 9hrs")  + xlab(NULL) #xlab("Gene expression TPM (Log2)") +

#tiff("ExpMethyl_cor_9hrs.tiff", width = 2.5, height = 3.5, units = "in",res = 300,compression = "lzw")
#ExpMethyl_cor_9hrs
#dev.off()
suppressWarnings(grid.arrange(ExpMethyl_cor_9hrs))

Gene expression at 12, 14 and 16 hrs embryos based on methylation from 11-12 hrs embryos - Fig 5I, middle

ExpMethyl_cor_12hrs <- embryo_Exp_Methyl_data %>% select(-c(`CpG_N_9hrs`:`CpG_N_24hrs`,`methylation_9hrs`,`methylation_24hrs`)) %>% 
  pivot_longer(cols = -c(gene_id,methylation_12hrs),names_to = "exp_stage",values_to="exp_count") %>% 
  mutate(exp_stage=factor(exp_stage,levels = c("gene_id","0-9hrs","11hrs","12hrs","14hrs","16hrs","20hrs","24hrs","24-60hrs"))) %>%
  mutate(exp_cat= ifelse(exp_count == 0, "0",
                         ifelse(between(exp_count,0,1),"≤ 1",
                                ifelse(between(exp_count,1,5),"≤ 5","≥ 5")))) %>% 
  filter(exp_stage %in% c("12hrs","14hrs","16hrs")) %>%
  mutate(exp_cat=factor(exp_cat,levels = c("0","≤ 1","≤ 5","≥ 5"))) %>%
  ggplot(aes(fill=exp_stage,x=exp_cat,y=methylation_12hrs)) + geom_boxplot(outlier.colour = "grey",outlier.size = 0.4,alpha=0.6)+
  ylim(NA,20) + # to print in notebook
  #scale_y_break(c(20, 95), scales = 0.01, ticklabels=c(95, 100)) + # to save figure
  scale_fill_manual(values=c("darkslategray","dodgerblue","darkorange1")) +  #scale_y_continuous(expand = c(0,0)) +
  geom_hline(aes(yintercept = 3), color="chocolate4", linetype="dashed", size=0.5) +
  geom_hline(aes(yintercept = 3), color="chocolate4", linetype="dashed", size=0.5) +
  theme(legend.title=element_blank(),legend.key.size = unit(0.5, 'cm'),legend.text = element_text(size=6),
        legend.position="top",legend.justification="right",legend.margin=margin(0,0,0,0),#legend.box.margin=margin(-20,-100,-10,-10),
        axis.text.x = element_text(size = 10,angle =0,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10), axis.title = element_text(size = 14),strip.text.x = element_text(size = 12),
        axis.text.x.top = element_blank(),axis.ticks.x.top = element_blank(),axis.line.x.top = element_blank()) + 
  ylab("Gene methylation % - 11-12 hrs")  + xlab(NULL)   #xlab("Gene expression TPM (Log2)") + 

# tiff("ExpMethyl_cor_12hrs.tiff", width = 2.5, height = 3.5, units = "in",res = 300,compression = "lzw")
# ExpMethyl_cor_12hrs
# dev.off()
suppressWarnings(grid.arrange(ExpMethyl_cor_12hrs))

Gene expression at 20 and 24-60 hrs embryos based on methylation from 24-60 hrs embryos - Fig 5I, right


ExpMethyl_cor_24hrs <- embryo_Exp_Methyl_data %>% select(-c(`CpG_N_9hrs`:`CpG_N_24hrs`,`methylation_9hrs`,`methylation_12hrs`)) %>% 
  pivot_longer(cols = -c(gene_id,methylation_24hrs),names_to = "exp_stage",values_to="exp_count") %>% 
  mutate(exp_stage=factor(exp_stage,levels = c("gene_id","0-9hrs","11hrs","12hrs","14hrs","16hrs","20hrs","24hrs","24-60hrs"))) %>%
  mutate(exp_cat= ifelse(exp_count == 0, "0",
                         ifelse(between(exp_count,0,1),"≤ 1",
                                ifelse(between(exp_count,1,5),"≤ 5","≥ 5")))) %>% 
  filter(exp_stage %in% c("24hrs","24-60hrs")) %>%
  mutate(exp_cat=factor(exp_cat,levels = c("0","≤ 1","≤ 5","≥ 5"))) %>%
  ggplot(aes(fill=exp_stage,x=exp_cat,y=methylation_24hrs)) + geom_boxplot(outlier.colour = "grey",outlier.size = 0.4,alpha=0.6)+ 
  ylim(NA,20) + # to print in notebook
  #scale_y_break(c(20, 95), scales = 0.01, ticklabels=c(95, 100)) + # to save figure
  scale_fill_manual(values=c("forestgreen","gainsboro","darkorange1")) +  #scale_y_continuous(expand = c(0,0)) +
  geom_hline(aes(yintercept = 3), color="chocolate4", linetype="dashed", size=0.5) +
  geom_hline(aes(yintercept = 3), color="chocolate4", linetype="dashed", size=0.5) +
  theme(legend.title=element_blank(),legend.key.size = unit(0.5, 'cm'),legend.text = element_text(size=6),
        legend.position="top",legend.justification="right",legend.margin=margin(0,0,0,0),#legend.box.margin=margin(-20,-100,-10,-10),
        axis.text.x = element_text(size = 10,angle =0,vjust = 0.65,hjust = 0.7),
        axis.text.y = element_text(size = 10), axis.title = element_text(size = 14),strip.text.x = element_text(size = 12),
        axis.text.x.top = element_blank(),axis.ticks.x.top = element_blank(),axis.line.x.top = element_blank()) + 
  ylab("Gene methylation % - 24-60 hrs") + xlab(NULL)

# tiff("ExpMethyl_cor_24hrs.tiff", width = 2.5, height = 3.5, units = "in",res = 300,compression = "lzw")
# ExpMethyl_cor_24hrs
# dev.off()
suppressWarnings(grid.arrange(ExpMethyl_cor_24hrs))

9.1 Methylation for different developmental gene categories - Fig 5J

11-12 hrs methylation

# setwd("/drives/ssd1/manuel/phaw/2022_analysis/wgbs_analysis/")
gene_categories <- read.table("/drives/ssd1/manuel/phaw/2022_analysis/mzt_analysis/dev_genes_categories.csv",header = T,stringsAsFactors = F,sep=",")

my_comparisons = list(c("Minor wave all","Minor wave zygotic"), c("Maternal","Minor wave all"),
                      c("Major wave all","Major wave zygotic"),c("Maternal","Minor wave zygotic"))#,c("Maternal","Major wave zygotic"))

ZGA_methylation_12h  <- geneBody_full_methData %>% #replace(is.na(.), 0) %>%
  mutate(Class = ifelse(gene %in% gene_categories$pz_minor_wave,"Minor wave zygotic",
                      ifelse(gene %in% gene_categories$minor_wave_allGenes,"Minor wave all",
                               ifelse(gene %in% gene_categories$pz_major_wave,"Major wave zygotic", 
                                      ifelse(gene %in% gene_categories$maternal_genes_noZGA,"Maternal",
                                             ifelse(gene %in% gene_categories$major_wave_allGenes,"Major wave all","rest")))))) %>% 
  mutate(Class = factor(Class,levels = c("Maternal","Minor wave all","Minor wave zygotic","Major wave all","Major wave zygotic"))) %>%
  filter(Class != "rest",class== "Cov12hrs") %>% #group_by(Class) %>% summarise(meanss=mean(tx_ln))
  ggplot(aes(x=Class, y=methylation,fill=Class),size=0.3) + geom_jitter(size=0.3, alpha=0.3,color="grey") + geom_violin(alpha=0.5) + theme_minimal() +
  ylim(NA,30)+
  #scale_y_break(c(30, 60), scales = 0.1, ticklabels=c(60, 100)) +# scale_y_continuous(expand = c(0, 50)) +
  xlab(NULL) + ylab("Gene methylation - 11-12 hrs") +
  stat_summary(fun=median, geom="point", shape=23, size=1.5, color="black", fill="red",alpha=1)+
  scale_fill_manual(name=" ", values=c("navyblue", "#2B83BA", "orange","firebrick4","seagreen4")) +
  theme(axis.text.x = element_text(angle = 20, vjust = 0.9, hjust=0.75,size=10),
        axis.text.y = element_text(size=8), axis.title.x=element_blank(),legend.position="none",
        axis.title.y = element_text(size = 14),
        axis.text.y.right = element_blank(),
        axis.line.y.right = element_blank(),
        axis.ticks.y.right = element_blank())# + stat_compare_means(comparisons = my_comparisons,label = "p.signif",size=2.5,vjust = 0)# + stat_compare_means(label.y = 8, label.x=1.5, size=5) 
#ZGA_methylation_12h

# tiff("ZGA_methylation_12h.tiff", width = 3, height = 3.5, units = "in",res = 800,compression = "lzw")
# ZGA_methylation_12h
# dev.off()
suppressWarnings(grid.arrange(ZGA_methylation_12h))

24-60 hrs methylation

ZGA_methylation_24_60h  <- geneBody_full_methData %>% #replace(is.na(.), 0) %>%
  mutate(Class = ifelse(gene %in% gene_categories$pz_minor_wave,"Minor wave zygotic",
                      ifelse(gene %in% gene_categories$minor_wave_allGenes,"Minor wave all",
                               ifelse(gene %in% gene_categories$pz_major_wave,"Major wave zygotic", 
                                      ifelse(gene %in% gene_categories$maternal_genes_noZGA,"Maternal",
                                             ifelse(gene %in% gene_categories$major_wave_allGenes,"Major wave all","rest")))))) %>% 
  mutate(Class = factor(Class,levels = c("Maternal","Minor wave all","Minor wave zygotic","Major wave all","Major wave zygotic"))) %>%
  filter(Class != "rest",class== "Cov24hrs") %>% #group_by(Class) %>% summarise(meanss=mean(tx_ln))
  ggplot(aes(x=Class, y=methylation,fill=Class),size=0.3) + geom_jitter(size=0.3, alpha=0.3,color="grey") + geom_violin(alpha=0.5) + theme_minimal() +
  ylim(NA,30)+
  #scale_y_break(c(30, 60), scales = 0.1, ticklabels=c(60, 100)) +# scale_y_continuous(expand = c(0, 50)) +
  xlab(NULL) + ylab("Gene methylation - 24-60 hrs") +
  stat_summary(fun=median, geom="point", shape=23, size=1.5, color="black", fill="red",alpha=1)+
  scale_fill_manual(name=" ", values=c("navyblue", "#2B83BA", "orange","firebrick4","seagreen4")) +
  theme(axis.text.x = element_text(angle = 20, vjust = 0.9, hjust=0.75,size=10),
        axis.text.y = element_text(size=8), axis.title.x=element_blank(),legend.position="none",
        axis.title.y = element_text(size = 14),
        axis.text.y.right = element_blank(),
        axis.line.y.right = element_blank(),
        axis.ticks.y.right = element_blank())# + stat_compare_means(comparisons = my_comparisons,label = "p.signif",size=2.5,vjust = 0)# + stat_compare_means(label.y = 8, label.x=1.5, size=5) 

suppressWarnings(grid.arrange(ZGA_methylation_24_60h))

LS0tCnRpdGxlOiAiM185IFdob2xlLWdlbm9tZSBETkEgbWV0aHlsYXRpb24gZHluYW1pY3MgZHVyaW5nICpQYXJoeWFsZSogZW1icnlvZ2VuZXNpcyIKYXV0aG9yOiAiTWFudWVsIEphcmEtRXNwZWpvIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKIyBJbnRyb2R1Y3Rpb24KVGhpcyBub3RlYm9vayBkZXNjcmliZXMgdGhlIGFuYWx5c2lzIGFuZCBpbnRlcnByZXRhdGlvbiBvZiBNZXRoeWwtU2VxIGRhdGEgZ2VuZXJhdGVkIGZvciB0aHJlZSBkZXZlbG9wbWVudGFsIHRpbWVwb2ludHM6ClN0YWdlMSAoUzEpOiAwLTkuMTUgaHJzClN0YWdlMiAoUzEpOiAxMS0xMiBocnMKU3RhZ2UzIChTMSk6IDI0LTYwIGhycwoKIyBNZXRoeWxhdGlvbiBkYXRhIHByb2Nlc3NpbmcgCgojIyBRdWFsaXR5IGNoZWNrIHVzaW5nICpGYXN0UUMqCgpgYGB7YmFzaH0KbWV0aHlsX3NlcV9yYXc9U3RhZ2UxXzJfRUtETDIwMDAxMjg0MC0xYV9ISEhGTURTWFlfTDJfMS5mcS5neiAjIEV4YW1wbGU6IFN0YWdlIDEsIFJlYWRzXzEKZWNobyAiU3RhZ2UxIHJhdyByZWFkc18xOiIgJG1ldGh5bF9zZXFfcmF3CiMuL3NvZnR3YXJlL0Zhc3RRQy9mYXN0cWMgJG1ldGh5bF9zZXFfcmF3IFN0YWdlMV8yX0VLREwyMDAwMTI4NDAtMWFfSEhIRk1EU1hZX0wyXzEuZnEuZ3ogCmBgYAoKIyMgUmVhZHMgdHJpbW1pbmcgdXNpbmcgKlRyaW1HYWxvcmUqCgpgYGB7YmFzaH0KI1J1bm5pbmcgb24gc3RhZ2UxIGRhdGEKfi9zb2Z0d2FyZS9UcmltR2Fsb3JlLTAuNi42L3RyaW1fZ2Fsb3JlIC0tcGFpcmVkICBTdGFnZTFfMl9FS0RMMjAwMDEyODQwLTFhX0hISEZNRFNYWV9MMl8xLmZxLmd6IFN0YWdlMV8yX0VLREwyMDAwMTI4NDAtMWFfSEhIRk1EU1hZX0wyXzIuZnEuZ3oKCmVjaG8gIlN0YWdlMSBjbGVhbiByZWFkczogU3RhZ2UxXzJfRUtETDIwMDAxMjg0MC0xYV9ISEhGTURTWFlfTDJfMV92YWxfMS5mcSBTdGFnZTFfMl9FS0RMMjAwMDEyODQwLTFhX0hISEZNRFNYWV9MMl8yX3ZhbF8yLmZxIgpgYGAKCiMjIE1hcHBpbmcgcmVhZHMgdG8gKlBoYXc1LjEqIGdlbm9tZQoKUnVubmluZyBiaXNtYXJrX2dlbm9tZV9wcmVwYXJhdGlvbgoKYGBge2Jhc2h9CiRwaGF3X2dlbm9tZT0vZHJpdmVzL3NzZDEvd2VpL2dlbm9tZS9waGF3X3NhbWJhQXNtLnNjYWZmX3NlcXNfZWRpdGVkU2NhZk5hbWVzLmZhCn4vc29mdHdhcmUvQmlzbWFyay0wLjIyLjMvYmlzbWFya19nZW5vbWVfcHJlcGFyYXRpb24gLS1wYXRoX3RvX2Jvd3RpZSB+L3NvZnR3YXJlL2Jvd3RpZTIvYm93dGllMi0yLjQuMi1zcmEtbGludXgteDg2XzY0LyAgCi0tdmVyYm9zZSAtLWJvd3RpZTIgJHBoYXdfZ2Vub21lCmBgYAoKUnVubmluZyBiaXNtYXJrX21hcHBpbmcKCmBgYHtiYXNofQp+L3NvZnR3YXJlL0Jpc21hcmstMC4yMi4zL2Jpc21hcmsgLS1ib3d0aWUyIC0tcGF0aF90b19ib3d0aWUyIH4vc29mdHdhcmUvYm93dGllMi9ib3d0aWUyLTIuNC4yLXNyYS1saW51eC14ODZfNjQvIAotLXNhbXRvb2xzX3BhdGggfi9zb2Z0d2FyZS9zYW10b29scy0xLjE3IC0tZ2Vub21lIC9kcml2ZXMvc3NkMS93ZWkvZ2Vub21lIC1OIDEgLUwgMjIgLS1zY29yZV9taW4gTCwwLC0wLjYgIC0xIC4vU3RhZ2UxXzJfRUtETDIwMDAxMjg0MC0xYV9ISEhGTURTWFlfTDJfMV92YWxfMS5mcSAtMiAuL1N0YWdlMV8yX0VLREwyMDAwMTI4NDAtMWFfSEhIRk1EU1hZX0wyXzJfdmFsXzIuZnEKCmVjaG8gIlN0YWdlMSBtYXBwZWQgcmVhZHM6IFN0YWdlMV8yX0VLREwyMDAwMTI4NDAtMWFfSEhIRk1EU1hZX0wyXzFfdmFsXzFfYmlzbWFya19idDJfcGUuYmFtIgpgYGAKCiMjIERlZHVwbGljYXRpb24KCmBgYHtiYXNofQp+L3NvZnR3YXJlL0Jpc21hcmstMC4yMi4zL2RlZHVwbGljYXRlX2Jpc21hcmsgLXAgLS1iYW0gU3RhZ2UxXzJfRUtETDIwMDAxMjg0MC0xYV9ISEhGTURTWFlfTDJfMV92YWxfMV9iaXNtYXJrX2J0Ml9wZS5iYW0KZWNobyAiU3RhZ2UxIGRlZHVwbGljYXRlZCByZWFkczogU3RhZ2UxXzJfRUtETDIwMDAxMjg0MC0xYV9ISEhGTURTWFlfTDJfMV92YWxfMV9iaXNtYXJrX2J0Ml9wZS5kZWR1cGxpY2F0ZWQuYmFtIgpgYGAKCiMjIE1ldGh5bGF0aW9uIGNhbGxpbmcKCmBgYHtiYXNofQojfi9zb2Z0d2FyZS9CaXNtYXJrLTAuMjIuMy9iaXNtYXJrX21ldGh5bGF0aW9uX2V4dHJhY3RvciAtcCAtLWNvbXByZWhlbnNpdmUgLS1zYW10b29sc19wYXRoIH4vc29mdHdhcmUvc2FtdG9vbHMtMS4xNyAtLWJlZEdyYXBoIC0tc2NhZmZvbGRzICAtLWN5dG9zaW5lX3JlcG9ydCAtLWdlbm9tZV9mb2xkZXIgL2RyaXZlcy9zc2QxL3dlaS9nZW5vbWUvIFN0YWdlMV8yX0VLREwyMDAwMTI4NDAtMWFfSEhIRk1EU1hZX0wyXzFfdmFsXzFfYmlzbWFya19idDJfcGUuZGVkdXBsaWNhdGVkLmJhbQplY2hvICJDb3ZlcmVkIENwR3MgLSBTdGFnZTEiCmhlYWQgLTUgL2RyaXZlcy9zc2QxL3dlaS9lbXNlcS9tYXAvbm9jdXQvUzEvUzFfQ3BHc3VtCmBgYAoKIyBTdW1tYXJpc2UgbWV0aHlsYXRpb24gbGV2ZWwgcGVyIHN0YWdlCgojIyBDcEcgY292ZXJhZ2UgZm9yIGFsbCBDUEdzIGluIHRoZSBnZW5vbWUgYWNyb3NzIHN0YWdlcyAtIEZpZyBTMTNBCgpgYGB7cn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KG1lc3NhZ2U9Rix3YXJuaW5nPUYsZWNobz1UKQojTG9hZCBsaWJyYXJpZXMKbGlicmFyeSh0aWR5cikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoY29sb3J0b29scykKbGlicmFyeShSc3VicmVhZCkKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGdnYnJlYWspIApsaWJyYXJ5KFZlbm5EaWFncmFtKQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShtZXRoeWxLaXQpCmBgYAoKCmBgYHtyfQojQ292ZXJhZ2UgZm9yIGFsbCBDUEdzIGluIHRoZSBnZW5vbWUKY292QWxsQ3BHXzlociA8LSByZWFkLnRhYmxlKCIvZHJpdmVzL3NzZDEvd2VpL2Zvcm1hbnVlbC9TMV9DcEdzdW0iLGhlYWRlciA9IEYpICNDb3ZlcmVkIENwR3Mgc3RhZ2UgMC05OjE1IGhycwpjb3ZBbGxDcEdfMTJociA8LSByZWFkLnRhYmxlKCIvZHJpdmVzL3NzZDEvd2VpL2Zvcm1hbnVlbC9TMl9DcEdzdW0iLGhlYWRlciA9IEYpICNDb3ZlcmVkIENwR3Mgc3RhZ2UgMTE6MTIgaHJzCmNvdkFsbENwR18yNF82MGhyIDwtIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS93ZWkvZm9ybWFudWVsL1MzX0NwR3N1bSIsaGVhZGVyID0gRikgI0NvdmVyZWQgQ3BHcyBzdGFnZSAyNDo2MCBocnMKCiNNZXJnZSBjb3ZlcmFnZSBkYXRhCmNvdkFsbENwR19hbGxTdGFnZXMgPC0gZHBseXI6OmJpbmRfcm93cyhsaXN0KGNvdkFsbENwR185aHIsY292QWxsQ3BHXzEyaHIsY292QWxsQ3BHXzI0XzYwaHIpLCAuaWQgPSAnc3RhZ2UnKSAlPiUgCiAgbXV0YXRlKHN0YWdlID0gcmVjb2RlKHN0YWdlLCAnMScgPSAnZW1iXzlocicsICcyJyA9ICdlbWJfMTJocicsICczJyA9ICdlbWJfMjRfNjBocicpKSAlPiUKICBtdXRhdGUoY292ZXJhZ2UgPSAoVjQgKyBWNSkpCmNvbG5hbWVzKGNvdkFsbENwR19hbGxTdGFnZXMpIDwtIGMoInN0YWdlIiwiU2NhZmZvbGQiLCJwb3MiLCJzdHJhbmQiLCJtQ3BHX3JlYWRzIiwiVW5tQ3BHX3JlYWRzIiwibWV0aHlsYXRpb25fbGV2ZWwiLCJjb3ZlcmFnZSIpCgpybShjb3ZBbGxDcEdfOWhyLGNvdkFsbENwR18xMmhyLGNvdkFsbENwR18yNF82MGhyKQpgYGAKCgpgYGB7cn0KY292QWxsQ3BHX2FsbFN0YWdlcyAlPiUgZ3JvdXBfYnkoc3RhZ2UpICU+JSBzdW1tYXJpc2UoY292TWVkaWFuID0gbWVkaWFuKGNvdmVyYWdlKSxjb3ZNZWFuID0gbWVhbihjb3ZlcmFnZSkpCgpjb3ZBbGxDcEdfYWxsU3RhZ2VzX2Rpc3RyaWJ1dGlvbiA8LSBjb3ZBbGxDcEdfYWxsU3RhZ2VzICAlPiUgbXV0YXRlKHN0YWdlPWZhY3RvcihzdGFnZSwgbGV2ZWxzID0gYygnZW1iXzlocicsJ2VtYl8xMmhyJywnZW1iXzI0XzYwaHInKSkpICU+JQogIGZpbHRlcihjb3ZlcmFnZSA8PSA1MCkgJT4lCiAgbXV0YXRlKGNvdmVyYWdlPWZhY3Rvcihjb3ZlcmFnZSwgbGV2ZWxzID0gYyhzZXEoMCw1MCwxKSkpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Y292ZXJhZ2UsZmlsbD1zdGFnZSkpICsgIGdlb21fYmFyKHN0YXQ9J2NvdW50JywgcG9zaXRpb249J2RvZGdlJykgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoc2VxKDAsNTAsMTApKSxicmVha3MgPXNlcSgwLDUwLDEwKSApICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIm9yYW5nZTIiLCJtaXN0eXJvc2U0IiwibWFyb29uIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLGxhYmVscz11bml0X2Zvcm1hdCh1bml0ID0gIk0iLHNjYWxlPTFlLTYpKSsgeWxhYigiQ291bnRzIChtaWxsaW9uKSIpICt4bGFiKCJXR0JTLXNlcSBjb3ZlcmFnZSIpICsKICAjc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9IGMoIjAiLCIyMCIsIjQwIiwiNjAiLCI4MCIsIjEwMCIpKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsYW5nbGUgPTAsdmp1c3QgPSAwLjY1KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpLGxlZ2VuZC5wb3NpdGlvbj1jKDAuOCwwLjg1KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpIAoKI3RpZmYoImNvdkFsbENwR19hbGxTdGFnZXNfZGlzdHJpYnV0aW9uLnRpZmYiLCB3aWR0aCA9IDUsIGhlaWdodCA9IDQsIHVuaXRzID0gImluIixyZXMgPSA0MDAsY29tcHJlc3Npb24gPSAibHp3IikKY292QWxsQ3BHX2FsbFN0YWdlc19kaXN0cmlidXRpb24gCiNkZXYub2ZmKCkKYGBgCiMjIFRpbWUtcG9pbnQgc3BlY2lmaWMgZnJhY3Rpb25hbCBtZXRoeWxhdGlvbiBsZXZlbHMgLSAgRmlnIDVBCgpgYGB7cn0KIyBQbG90IGF2ZXJhZ2UgbWV0aHlsYXRpb24gZm9yIGFsbCBjb3ZlcmVkIENwR2EgKGNvdW50cyA+PSA1KSAKbWV0aF9hbGxDb3ZDcEdfYWxsU3RhZ2VzX3BlclN0YWdlIDwtIGNvdkFsbENwR19hbGxTdGFnZXMgJT4lIGZpbHRlcihjb3ZlcmFnZSA+PSA1KSAlPiUgCiAgbXV0YXRlKHN0YWdlPWZhY3RvcihzdGFnZSwgbGV2ZWxzID0gYygnZW1iXzlocicsJ2VtYl8xMmhyJywnZW1iXzI0XzYwaHInKSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzdGFnZSwgeSA9IG1ldGh5bGF0aW9uX2xldmVsLGZpbGw9IHN0YWdlKSkgKyBnZW9tX2JhciggcG9zaXRpb249J2RvZGdlJyxzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz0gYygiOSBocnMiLCIxMS0xMiBocnMiLCIyNC02MCBocnMiKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJvcmFuZ2UyIiwibWlzdHlyb3NlNCIsIm1hcm9vbiIpKSArIAogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLGFuZ2xlID0zMCx2anVzdCA9IDAuNjUsaGp1c3QgPSAwLjcpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LngudG9wID0gZWxlbWVudF9ibGFuaygpLGF4aXMudGlja3MueC50b3AgPSBlbGVtZW50X2JsYW5rKCksYXhpcy5saW5lLngudG9wID0gZWxlbWVudF9ibGFuaygpKSArIAogIHhsYWIoTlVMTCkgKyB5bGFiKCJBdmVyYWdlIG1ldGh5bGF0aW9uICUiKSArIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpIAogICNzY2FsZV95X2JyZWFrKGMoMTAsIDkwKSwgc2NhbGVzID0gMC4wMywgdGlja2xhYmVscz1jKDkwLCAxMDApKQoKI3RpZmYoIm1ldGh5bF9sZXZlbF9wZXJTdGFnZV9hbGxDb3ZDcEcudGlmZiIsIHdpZHRoID0gMS41LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIscmVzID0gNDAwLGNvbXByZXNzaW9uID0gImx6dyIpCm1ldGhfYWxsQ292Q3BHX2FsbFN0YWdlc19wZXJTdGFnZQojZGV2Lm9mZigpCmBgYAoKIyMgTWV0aHlsYXRpb24gbGV2ZWwgZGlzdHJpYnV0aW9uIGZvciBtQ3BHcyAobWV0aHlsYXRpb24gPj0gMjApIC0gIEZpZyBTMTNCCgpgYGB7cn0KbUNwZ19tZXRoeWxEaXN0cmlidXRpb24gPC0gY292QWxsQ3BHX2FsbFN0YWdlcyAlPiUgZmlsdGVyKGNvdmVyYWdlID49IDUsIG1ldGh5bGF0aW9uX2xldmVsID49IDIwKSAlPiUgCiAgbXV0YXRlKHN0YWdlPWZhY3RvcihzdGFnZSwgbGV2ZWxzID0gYygnZW1iXzlocicsJ2VtYl8xMmhyJywnZW1iXzI0XzYwaHInKSkpICU+JSAKICBnZ3Bsb3QoKSArIAogIGdlb21faGlzdG9ncmFtKGFlcyh4PW1ldGh5bGF0aW9uX2xldmVsLHk9Li5jb3VudC4uKSkgKyBmYWNldF93cmFwKH5zdGFnZSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksbGFiZWxzPXVuaXRfZm9ybWF0KHVuaXQgPSAiTSIsc2NhbGU9MWUtNiksbGltaXRzID0gYygwLDE0MDAwMDApKSsgCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsYW5nbGUgPTMwLHZqdXN0ID0gMC42NSksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSxsZWdlbmQucG9zaXRpb249YygwLjEsMC44NSksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSAKCiN0aWZmKCJtQ3BnX21ldGh5bERpc3RyaWJ1dGlvbi50aWZmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNCwgdW5pdHMgPSAiaW4iLHJlcyA9IDQwMCxjb21wcmVzc2lvbiA9ICJsenciKQptQ3BnX21ldGh5bERpc3RyaWJ1dGlvbiAKI2Rldi5vZmYoKQpgYGAKIyMgTWV0aHlsYXRpb24gYnkgZ2Vub21pYyBmZWF0dXJlIC0gRmlnIDVCIGFuZCBTMTNECgpgYGB7cn0KI09wZW4gd2l0aCBzdW1tYXJpc2VkIG1ldGh5bGF0aW9uIGRhdGEgcGVyIHN0YWdlIGFuZCBmZWF0dXJlCnBlckZlYXR1cmVfTWV0aFN0YXRzIDwtIHJlYWQudGFibGUoIi4uL3dnYnNfYW5hbHlzaXMvd2hvbGVnZW5vbWVfdGUiLGhlYWRlciA9IFQpCmNvbG5hbWVzKHBlckZlYXR1cmVfTWV0aFN0YXRzKSA8LSBjKCJyZWdpb24iLCI1WENvdl9DcEdzIiwibUNwR3MiLCJtQ3BHc19wZXJjZW50IiwibWV0aHlsYXRpb25fbGV2ZWwiLCJzdGFnZSIsIkdyb3VwIikKcGVyRmVhdHVyZV9NZXRoU3RhdHMKYGBgCgpgYGB7cn0KI3NldHdkKCIvZHJpdmVzL3NzZDEvbWFudWVsL3BoYXcvMjAyMl9hbmFseXNpcy93Z2JzX2FuYWx5c2lzLyIpCiNQbG90IGZyYWN0aW9uIG9mIG1ldGh5bGF0ZWQgQ3BHcyBwZXIgZmVhdHVyZSAtIEZpZyAxM0QKbUNwR19wZXJjZW50X2J5RmVhdHVyZSA8LSBwZXJGZWF0dXJlX01ldGhTdGF0cyAlPiUgbXV0YXRlKHN0YWdlID0gcmVjb2RlKHN0YWdlLCAnUzEnID0gJzkgaHJzJywgJ1MyJyA9ICcxMS0xMiBocnMnLCAnUzMnID0gJzI0XzYwIGhycycpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cmVnaW9uICwgeSA9IG1DcEdzX3BlcmNlbnQsIGZpbGw9c3RhZ2UpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiLGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAwLjEpICsKICBmYWNldF93cmFwKH4gR3JvdXAsc2NhbGVzPSJmcmVlX3giKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIm9yYW5nZTIiLCJtaXN0eXJvc2U0IiwibWFyb29uIikpICsgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLGFuZ2xlID0zMCx2anVzdCA9IDAuNjUsaGp1c3QgPSAwLjcpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksbGVnZW5kLnBvc2l0aW9uPWMoMC4xLDAuODUpLGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JyksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCNzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkgKyB4bGFiKE5VTEwpICsgeWxhYigiUGVyY2VudCBvZiBtQ3BHIikgCgojUGxvdCBmcmFjdGlvbmFsIG1ldGh5bGF0aW9uIHBlciBmZWF0dXJlIC0gRmlnIDVCIAptQ3BHX2xldmVsX2J5RmVhdHVyZSA8LSBwZXJGZWF0dXJlX01ldGhTdGF0cyAlPiUgbXV0YXRlKHN0YWdlID0gcmVjb2RlKHN0YWdlLCAnUzEnID0gJzkgaHJzJywgJ1MyJyA9ICcxMS0xMiBocnMnLCAnUzMnID0gJzI0XzYwIGhycycpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cmVnaW9uICwgeSA9IG1ldGh5bGF0aW9uX2xldmVsLCBmaWxsPXN0YWdlKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIixjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMC4xKSArCiAgZmFjZXRfd3JhcCh+IEdyb3VwLHNjYWxlcz0iZnJlZV94IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJvcmFuZ2UyIiwibWlzdHlyb3NlNCIsIm1hcm9vbiIpKSArIAogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLGFuZ2xlID0zMCx2anVzdCA9IDAuNjUsaGp1c3QgPSAwLjcpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksbGVnZW5kLnBvc2l0aW9uPWMoMC4xLDAuODUpLGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JyksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpICsgeGxhYihOVUxMKSArIHlsYWIoIk1ldGh5bGF0aW9uICUiKSAKCiN0aWZmKCJtQ3BHX3BlcmNlbnRfYnlGZWF0dXJlLnRpZmYiLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMsIHVuaXRzID0gImluIixyZXMgPSA0MDAsY29tcHJlc3Npb24gPSAibHp3IikKbUNwR19wZXJjZW50X2J5RmVhdHVyZSAjJT4lIGZpbHRlcihzdGFnZSA9PSJlbWJfOWhyIikgJT4lIGZpbHRlcihtZXRoeWxhdGlvbl9sZXZlbCA9PSAiMTAwIiApICU+JSBkaW0oKQojZGV2Lm9mZigpCgojdGlmZigibUNwR19sZXZlbF9ieUZlYXR1cmUudGlmZiIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iLHJlcyA9IDQwMCxjb21wcmVzc2lvbiA9ICJsenciKQptQ3BHX2xldmVsX2J5RmVhdHVyZSAjJT4lIGZpbHRlcihzdGFnZSA9PSJlbWJfOWhyIikgJT4lIGZpbHRlcihtZXRoeWxhdGlvbl9sZXZlbCA9PSAiMTAwIiApICU+JSBkaW0oKQojZGV2Lm9mZigpCmBgYAojIyBEaXN0cmlidXRpb24gb2YgY292ZXJlZCBDcEdzIGFjcm9zcyBnZW5vbWljIGZlYXR1cmVzIC0gRmlnIFMxM0MKCmBgYHtyfQojc2V0d2QoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvIikKcGVyR2VuZUZlYXRfTWV0aFN0YXRzX2FsbFN0YWdlcyA8LSBwZXJGZWF0dXJlX01ldGhTdGF0cyAlPiUgbXV0YXRlKHN0YWdlID0gcmVjb2RlKHN0YWdlLCAnUzEnID0gJzkgaHJzJywgJ1MyJyA9ICcxMS0xMiBocnMnLCAnUzMnID0gJzI0LTYwIGhycycpKSAlPiUKICBmaWx0ZXIoR3JvdXAgPT0gIkdlbmUiLHJlZ2lvbiAhPSAiR2VuZWJvZHkiKSAlPiUgdGliYmxlKCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN0YWdlLCB5ID0gYDVYQ292X0NwR3NgLGZpbGw9IHJlZ2lvbikpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbj0nZmlsbCcpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsgeWxhYigiQ292ZXJlZCBDcEdzIGZyYWN0aW9uIikgKyB4bGFiKE5VTEwpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikrCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsYW5nbGUgPTMwLHZqdXN0ID0gMC42NSksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwjbGVnZW5kLnBvc2l0aW9uPWMoMC4xLDAuODUpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSxzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgCgpwZXJURXNfTWV0aFN0YXRzX2FsbFN0YWdlcyA8LXBlckZlYXR1cmVfTWV0aFN0YXRzICU+JSBtdXRhdGUoc3RhZ2UgPSByZWNvZGUoc3RhZ2UsICdTMScgPSAnOSBocnMnLCAnUzInID0gJzExLTEyIGhycycsICdTMycgPSAnMjQtNjAgaHJzJykpICU+JQogIGZpbHRlcihHcm91cCA9PSAiVEUiLHJlZ2lvbiAhPSAiVEUiKSAlPiUgdGliYmxlKCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN0YWdlLCB5ID0gYDVYQ292X0NwR3NgLGZpbGw9IHJlZ2lvbikpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbj0nZmlsbCcpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsgeWxhYigiQ292ZXJlZCBDcEdzIGZyYWN0aW9uIikgKyB4bGFiKE5VTEwpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpKwogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLGFuZ2xlID0zMCx2anVzdCA9IDAuNTUpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksI2xlZ2VuZC5wb3NpdGlvbj1jKDAuMSwwLjg1KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpIAoKI3RpZmYoIk1ldGhTdGF0c19hbGxTdGFnZXMudGlmZiIsIHdpZHRoID0gNi41LCBoZWlnaHQgPSA1LCB1bml0cyA9ICJpbiIscmVzID0gNDAwLGNvbXByZXNzaW9uID0gImx6dyIpCmdnYXJyYW5nZShwZXJHZW5lRmVhdF9NZXRoU3RhdHNfYWxsU3RhZ2VzLHBlclRFc19NZXRoU3RhdHNfYWxsU3RhZ2VzLG5yb3cgPSAxLG5jb2wgPSAyKQoKI2Rldi5vZmYoKQpgYGAKCiMgRHluYW1pY3Mgb2YgRE5BIE1ldGh5bG9tZXMgZm9yIEVhcmx5IEVtYnJ5b3MKSSBhaW1lZCB0byBpZGVudGlmeSBkaWZmZXJlbnRpYWwgbWV0aHlsYXRlZCBDcEdzIGJldHdlZW4gc3RhZ2VzIGFuZCBuZXh0IGludGVycm9nYXRlIGlmIHRoaXMgY2hhbmdlcyBhcmUgcHJldmFsZW50IGluIHNwZWNpZmljIGdlbm9taWMgcmVnaW9ucy4gT25seSBpbmNsdWRlZCBpbiB0aGUgYW5hbHlzaXMgQ3BHcyB3aXRoIGNvdmVyYWdlID49NQoKIyMgUmVhZCB0aGUgZmlsZXMgdG8gYSBtZXRoeWxSYXdMaXN0IG9iamVjdDogbXlvYmoKCmBgYHtyfQptZXRoeWxzZXFfZGlyIDwtICIvZHJpdmVzL3NzZDEvd2VpL2Vtc2VxL3N1bSIKbWV0aHlsc2VxX2ZpbGVzIDwtIGdyZXAoIkNwR19yZXBvcnQudHh0X0NHX21ldGh5a2l0LnR4dDIkIixsaXN0LmZpbGVzKG1ldGh5bHNlcV9kaXIsZnVsbC5uYW1lcyA9IFQpLHZhbHVlPVRSVUUpCgpteW9iaj1tZXRoUmVhZChhcy5saXN0KG1ldGh5bHNlcV9maWxlc1szOjZdKSwKICAgICAgICAgICBzYW1wbGUuaWQ9bGlzdCgiczExaCIsInMxMWgiLCJzMjRoIiwiczI0aCIpLAogICAgICAgICAgIGFzc2VtYmx5PSJwaGF3NTEiLAogICAgICAgICAgIHRyZWF0bWVudD1jKDAsMCwxLDEpLAogICAgICAgICAgIGNvbnRleHQ9IkNwRyIsbWluY292ID0gNSkKYGBgCgoKYGBge3J9CmhlYWQobXlvYmpbWzRdXSkKYGBgClF1YWxpdHkgY2hlY2sKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTh9CmdldE1ldGh5bGF0aW9uU3RhdHMobXlvYmpbWzFdXSxwbG90PVRSVUUsYm90aC5zdHJhbmRzPUZBTFNFKSAjOWhycwpnZXRNZXRoeWxhdGlvblN0YXRzKG15b2JqW1syXV0scGxvdD1UUlVFLGJvdGguc3RyYW5kcz1GQUxTRSkgIzlocnMKZ2V0TWV0aHlsYXRpb25TdGF0cyhteW9ialtbM11dLHBsb3Q9VFJVRSxib3RoLnN0cmFuZHM9RkFMU0UpICMxMS0xMmhycwpnZXRNZXRoeWxhdGlvblN0YXRzKG15b2JqW1s0XV0scGxvdD1UUlVFLGJvdGguc3RyYW5kcz1GQUxTRSkgIzExLTEyaHJzCmBgYApNZXJnaW5nIHNhbXBsZXMgaW50byBhIHNpbmdsZSB0YWJsZQogCmBgYHtyfQptZXRoPW1ldGh5bEtpdDo6dW5pdGUobXlvYmosIGRlc3RyYW5kPUZBTFNFKQpgYGAKCmBgYHtyfQpjbHVzdGVyU2FtcGxlcyhtZXRoLCBkaXN0PSJjb3JyZWxhdGlvbiIsIG1ldGhvZD0id2FyZCIsIHBsb3Q9VFJVRSkKYGBgCmBgYHtyfQpwYz1QQ0FTYW1wbGVzKG1ldGgsb2JqLnJldHVybiA9IFRSVUUsIGFkai5saW09YygxLDEpKQpgYGAKCgojIyBGaWx0ZXJpbmcgQ3BHcyBiYXNlZCBvbiB2YXJpYXRpb24KCkNhbGN1bGF0ZSBwZXIgQ3BHIHZhcmlhdGlvbgoKYGBge3J9CnBtPXBlcmNNZXRoeWxhdGlvbihtZXRoKSAjIGdldCBwZXJjZW50IG1ldGh5bGF0aW9uIG1hdHJpeAptZHM9bWF0cml4U3RhdHM6OnJvd1NkcyhwbSkgIyBjYWxjdWxhdGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIENwR3MKaGVhZChtZXRoW21kcz41LF0pCmBgYApIaXN0b2dyYW0gb2YgQ3BHIHZhcmlhdGlvbgoKYGBge3J9Cmhpc3QobWRzLGNvbD0iZ2FpbnNib3JvIix4bGFiPSJTdGQuIGRldi4gcGVyIENwRyIsYnJlYWtzID0gMTAwKQpgYGAKCktlZXAgQ3BHcyB3aXRoIHN0YW5kYXJkIGRldmlhdGlvbnMgbGFyZ2VyIHRoYW4gMiUgLSBDbHVzdGVyIHNhbXBsZXMKCmBgYHtyfQptZXRoIDwtIG1ldGhbbWRzPjIsXQpwcmludChwYXN0ZTAoIiMgb2YgQ3BHcyBmb3JuIGRvd25zdHJlYW0gYW5hbHlzaXM6ICIsbnJvdyhtZXRoKSkpCmBgYAoKIyMgRXh0cmFjdGluZyBkaWZmZXJlbnRpYWwgbWV0aHlsYXRlZCBDcEdzLiA5aHJzIHRvIDExIGhycyB0cmFuc3Rpb24KU2FtcGxlcyBwZXIgY29uZGl0aW9ucyB3ZXJlIHB1bGxlZCBhbmQgRmlzaGVyJ3MgZXhhY3QgdGVzdCB3YXMgYXBwbGllZC4KCmBgYHtyfQpnZXRTYW1wbGVJRChtZXRoKQpwb29sZWQubWV0aD1wb29sKG1ldGgsc2FtcGxlLmlkcz1jKCJzMTFoIiwiczI0aCIpKQpkbS5wb29sZWRmPWNhbGN1bGF0ZURpZmZNZXRoKHBvb2xlZC5tZXRoKQpgYGAKCkdldCBkaWZmZXJlbnRpYWxseSBtZXRoeWxhdGVkIGJhc2VzL3JlZ2lvbnMgCgpgYGB7cn0KIyBBbGwgc2l0ZXMKYWxsLmRpZmY9Z2V0TWV0aHlsRGlmZihkbS5wb29sZWRmLGRpZmZlcmVuY2U9NSxxdmFsdWU9MC4wNSx0eXBlPSJhbGwiKQoKIyBnZXQgaHlwZXItbWV0aHlsYXRlZApoeXBlcj1nZXRNZXRoeWxEaWZmKGRtLnBvb2xlZGYsZGlmZmVyZW5jZT01LHF2YWx1ZT0wLjA1LHR5cGU9Imh5cGVyIikKCiMgZ2V0IGh5cG8tbWV0aHlsYXRlZApoeXBvPWdldE1ldGh5bERpZmYoZG0ucG9vbGVkZixkaWZmZXJlbmNlPTUscXZhbHVlPTAuMDUsdHlwZT0iaHlwbyIpCmBgYAoKIyMgRGlmZmVyZW50aWFsbHkgbWV0aHlsYXRlZCBSZWdpb25zCgpUaWxlIHRoZSBnZW5vbWUgd2l0aCB3aW5kb3dzIG9mIDEwMDBicCBsZW5ndGggYW5kIDEwMDAgYnAgc3RlcC1zaXplIAoKIyBHZW5lIGJvZHkgKCstMmtiKSBtZXRoeWxhdGlvbiBhbmFseXNpcyAtIEZpZyA1QwoKUHJvY2VzcyBhbmQgc3VtbWFyaXNlIG1ldGh5bGF0aW9uIHBlciB3aW5kb3cgYWNyb3NzIGdlbmVzCkVhY2ggZ2VuZSB3YXMgc3BsaXQgaW50byAxMDAgd2luZG93cywgQ3BHcyB3ZXJlIG1hcHBlZCB0byBlYWNoIHdpbmRvdyBhbmQgdGhlIGF2ZXJhZ2UgbWV0aHlsYXRpb24gcGVyIHdpbmRvdyB3YXMgZXN0aW1hdGVkLiBUaGUgc2FtZSBwcm9jZXNzIHdhcyBwZXJmb3JtZWQgb24gMmtiIHVwc3RyZWFtIGFuZCBkb3duc3RyZWFtIHJlZ2lvbnMsIHdoaWNoIHdlcmUgc3BsaXQgaW50byAyMCB3aW5kb3dzCgpTdW1tYXJpc2luZyBnZW5lIGJvZHkgbWV0aHlsYXRpb24gcGVyIHN0YWdlCgpgYGB7cn0KdGlsZXM9dGlsZU1ldGh5bENvdW50cyhteW9iaix3aW4uc2l6ZT0xMDAwLHN0ZXAuc2l6ZT0xMDAwKQojaGVhZCh0aWxlc1tbMV1dLDMpCmBgYAoKQ29tYmluZSBpbnRvIHNpbmdsZSBvYmplY3QKCmBgYHtyfQptZXRoX2J5UmVnaW9uPW1ldGh5bEtpdDo6dW5pdGUodGlsZXMsIGRlc3RyYW5kPUZBTFNFKQpgYGAKCkV4dHJhY3RpbmcgZGlmZmVyZW50aWFsIG1ldGh5bGF0ZWQgcmVnaW9ucy4gMTFocnMgdG8gMjRocnMgdHJhbnN0aW9uClNhbXBsZXMgcGVyIGNvbmRpdGlvbnMgd2VyZSBwdWxsZWQgYW5kIEZpc2hlcidzIGV4YWN0IHRlc3Qgd2FzIGFwcGxpZWQuCgpgYGB7cn0KZ2V0U2FtcGxlSUQobWV0aF9ieVJlZ2lvbikKcG9vbGVkLm1ldGhSZWdpb249cG9vbChtZXRoX2J5UmVnaW9uLHNhbXBsZS5pZHM9YygiczExaCIsInM5aCIpKQpkbS5wb29sZWRmX2J5UmVnaW9uPWNhbGN1bGF0ZURpZmZNZXRoKHBvb2xlZC5tZXRoUmVnaW9uKQpgYGAKCmBgYHtyfQojIEFsbCBzaXRlcwphbGwuZGlmZj1nZXRNZXRoeWxEaWZmKGRtLnBvb2xlZGZfYnlSZWdpb24sZGlmZmVyZW5jZT01LHF2YWx1ZT0wLjA1LHR5cGU9ImFsbCIpCnByaW50KHBhc3RlMCgiQWxsIGRpZmZNZXRoOiIsbnJvdyhhbGwuZGlmZikpKQoKIyBnZXQgaHlwZXItbWV0aHlsYXRlZApoeXBlcj1nZXRNZXRoeWxEaWZmKGRtLnBvb2xlZGZfYnlSZWdpb24sZGlmZmVyZW5jZT01LHF2YWx1ZT0wLjA1LHR5cGU9Imh5cGVyIikKcHJpbnQocGFzdGUwKCJBbGwgZGlmZk1ldGg6Iixucm93KGh5cGVyKSkpCgojIGdldCBoeXBvLW1ldGh5bGF0ZWQKaHlwbz1nZXRNZXRoeWxEaWZmKGRtLnBvb2xlZGZfYnlSZWdpb24sZGlmZmVyZW5jZT01LHF2YWx1ZT0wLjA1LHR5cGU9Imh5cG8iKQpwcmludChwYXN0ZTAoIkFsbCBkaWZmTWV0aDoiLG5yb3coaHlwbykpKQoKYGBgCgpJbnRlcnNlY3Qgd2l0aCBnZW5pYyBhbmQgVEUgZWxlbWVudHMKCmBgYHtyfQojQ2FsbCB3aW5kb3ctYmFzZWQgbWV0aHlsYXRpb24gZmlsZXMgcGVyIHN0YWdlCnMxX2dlbmVib2R5X3cxMDAgPC0gcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL3dlaS9nZW5vbWUvZ2VuZWJvZHkvbm9zdHJhbmQvUzFfZ2VuZWJvZHlfd2luMTAwXzVfc3VtIiwgaGVhZGVyID0gRiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHMxX2dlbmVib2R5X3cxMDApIDwtIGMoImdlbmVfaWQiLCJ3aW5kb3ciLCJjcGdfY291bnQiLCJtZXRoeWxhdGlvbiIpCnMyX2dlbmVib2R5X3cxMDAgPC0gcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL3dlaS9nZW5vbWUvZ2VuZWJvZHkvbm9zdHJhbmQvUzJfZ2VuZWJvZHlfd2luMTAwXzVfc3VtIiwgaGVhZGVyID0gRiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHMyX2dlbmVib2R5X3cxMDApIDwtIGMoImdlbmVfaWQiLCJ3aW5kb3ciLCJjcGdfY291bnQiLCJtZXRoeWxhdGlvbiIpCnMzX2dlbmVib2R5X3cxMDAgPC0gcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL3dlaS9nZW5vbWUvZ2VuZWJvZHkvbm9zdHJhbmQvUzNfZ2VuZWJvZHlfd2luMTAwXzVfc3VtIiwgaGVhZGVyID0gRiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHMzX2dlbmVib2R5X3cxMDApIDwtIGMoImdlbmVfaWQiLCJ3aW5kb3ciLCJjcGdfY291bnQiLCJtZXRoeWxhdGlvbiIpCgojIFN1bW1hcmlzZSBmaWxlcywgZXN0aW1hdGluZyB3aW5kb3ctYmFzZWQgYXZlcmFnZSBtZXRoeWxhdGlvbiBhY3Jvc3MgZ2VuZXMKczFfZ2VuZWJvZHlfdzEwMCA8LSBzMV9nZW5lYm9keV93MTAwICU+JQogIG11dGF0ZSh3aW5kb3c9cGFzdGUwKCJ3Iix3aW5kb3cpKSAlPiUgcGl2b3Rfd2lkZXIoLSBjcGdfY291bnQsbmFtZXNfZnJvbSA9IHdpbmRvdyx2YWx1ZXNfZnJvbSA9IG1ldGh5bGF0aW9uKSAKczFfZ2VuZWJvZHlfdzEwMCA8LSBzMV9nZW5lYm9keV93MTAwWyxjKCJnZW5lX2lkIixwYXN0ZTAoInciLHNlcSgxOjEwMCkpKV0KCnMyX2dlbmVib2R5X3cxMDAgPC0gczJfZ2VuZWJvZHlfdzEwMCAgJT4lCiAgbXV0YXRlKHdpbmRvdz1wYXN0ZTAoInciLHdpbmRvdykpICU+JSBwaXZvdF93aWRlcigtIGNwZ19jb3VudCxuYW1lc19mcm9tID0gd2luZG93LHZhbHVlc19mcm9tID0gbWV0aHlsYXRpb24pIApzMl9nZW5lYm9keV93MTAwIDwtIHMyX2dlbmVib2R5X3cxMDBbLGMoImdlbmVfaWQiLHBhc3RlMCgidyIsc2VxKDE6MTAwKSkpXQoKczNfZ2VuZWJvZHlfdzEwMCA8LSBzM19nZW5lYm9keV93MTAwICAlPiUKICBtdXRhdGUod2luZG93PXBhc3RlMCgidyIsd2luZG93KSkgJT4lIHBpdm90X3dpZGVyKC0gY3BnX2NvdW50LG5hbWVzX2Zyb20gPSB3aW5kb3csdmFsdWVzX2Zyb20gPSBtZXRoeWxhdGlvbikgCnMzX2dlbmVib2R5X3cxMDAgPC0gczNfZ2VuZWJvZHlfdzEwMFssYygiZ2VuZV9pZCIscGFzdGUwKCJ3IixzZXEoMToxMDApKSldCgojIEZpbmFsIGRhdGEKczFfZ2VuZWJvZHlfdzEwMCA8LSBzMV9nZW5lYm9keV93MTAwICU+JSBzZWxlY3QoLWdlbmVfaWQpICU+JSBzdW1tYXJpc2VfYWxsKG1lYW4sbmEucm0gPSBUUlVFKQpzMl9nZW5lYm9keV93MTAwIDwtIHMyX2dlbmVib2R5X3cxMDAgJT4lIHNlbGVjdCgtZ2VuZV9pZCkgJT4lIHN1bW1hcmlzZV9hbGwobWVhbixuYS5ybSA9IFRSVUUpCnMzX2dlbmVib2R5X3cxMDAgPC0gczNfZ2VuZWJvZHlfdzEwMCAlPiUgc2VsZWN0KC1nZW5lX2lkKSAlPiUgc3VtbWFyaXNlX2FsbChtZWFuLG5hLnJtID0gVFJVRSkKYGBgCgoKYGBge3J9CnMxX2dlbmVib2R5X3cxMDAKczJfZ2VuZWJvZHlfdzEwMApzM19nZW5lYm9keV93MTAwCmBgYAoKU3VtbWFyaXppbmcgMmtiIGRvd25zdHJlYW0gZ2VuZSByZWdpb24gcGVyIHN0YWdlCgpgYGB7cn0KI0NhbGwgd2luZG93LWJhc2VkIG1ldGh5bGF0aW9uIGZpbGVzIHBlciBzdGFnZQpzMV9kb3duXzIwIDwtIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS93ZWkvZ2Vub21lL2Rvd24vbm9zdHJhbmQvUzFfZG93bjJrYl93aW4yMF81X3N1bSIsIGhlYWRlciA9IEYsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhzMV9kb3duXzIwKSA8LSBjKCJnZW5lX2lkIiwid2luZG93IiwiY3BnX2NvdW50IiwibWV0aHlsYXRpb24iKQpzMl9kb3duXzIwIDwtIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS93ZWkvZ2Vub21lL2Rvd24vbm9zdHJhbmQvUzJfZG93bjJrYl93aW4yMF81X3N1bSIsIGhlYWRlciA9IEYsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhzMl9kb3duXzIwKSA8LSBjKCJnZW5lX2lkIiwid2luZG93IiwiY3BnX2NvdW50IiwibWV0aHlsYXRpb24iKQpzM19kb3duXzIwIDwtIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS93ZWkvZ2Vub21lL2Rvd24vbm9zdHJhbmQvUzNfZG93bjJrYl93aW4yMF81X3N1bSIsIGhlYWRlciA9IEYsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhzM19kb3duXzIwKSA8LSBjKCJnZW5lX2lkIiwid2luZG93IiwiY3BnX2NvdW50IiwibWV0aHlsYXRpb24iKQoKIyBTdW1tYXJpc2UgZmlsZXMsIGVzdGltYXRpbmcgd2luZG93LWJhc2VkIGF2ZXJhZ2UgbWV0aHlsYXRpb24gYWNyb3NzIGdlbmVzCnMxX2Rvd25fMjAgPC0gczFfZG93bl8yMCAlPiUKICBtdXRhdGUod2luZG93PXBhc3RlMCgidyIsd2luZG93KSkgJT4lIHBpdm90X3dpZGVyKC0gY3BnX2NvdW50LG5hbWVzX2Zyb20gPSB3aW5kb3csdmFsdWVzX2Zyb20gPSBtZXRoeWxhdGlvbikgCnMxX2Rvd25fMjAgPC0gczFfZG93bl8yMFssYygiZ2VuZV9pZCIscGFzdGUwKCJ3IixzZXEoMToyMCkpKV0KCnMyX2Rvd25fMjAgPC0gczJfZG93bl8yMCAgJT4lCiAgbXV0YXRlKHdpbmRvdz1wYXN0ZTAoInciLHdpbmRvdykpICU+JSBwaXZvdF93aWRlcigtIGNwZ19jb3VudCxuYW1lc19mcm9tID0gd2luZG93LHZhbHVlc19mcm9tID0gbWV0aHlsYXRpb24pIApzMl9kb3duXzIwIDwtIHMyX2Rvd25fMjBbLGMoImdlbmVfaWQiLHBhc3RlMCgidyIsc2VxKDE6MjApKSldCgpzM19kb3duXzIwIDwtIHMzX2Rvd25fMjAgICU+JQogIG11dGF0ZSh3aW5kb3c9cGFzdGUwKCJ3Iix3aW5kb3cpKSAlPiUgcGl2b3Rfd2lkZXIoLSBjcGdfY291bnQsbmFtZXNfZnJvbSA9IHdpbmRvdyx2YWx1ZXNfZnJvbSA9IG1ldGh5bGF0aW9uKSAKczNfZG93bl8yMCA8LSBzM19kb3duXzIwWyxjKCJnZW5lX2lkIixwYXN0ZTAoInciLHNlcSgxOjIwKSkpXQoKIyBGaW5hbCBkYXRhCnMxX2Rvd25fMjAgPC0gczFfZG93bl8yMCAlPiUgc2VsZWN0KC1nZW5lX2lkKSAlPiUgc3VtbWFyaXNlX2FsbChtZWFuLG5hLnJtID0gVFJVRSkKczJfZG93bl8yMCA8LSBzMl9kb3duXzIwICU+JSBzZWxlY3QoLWdlbmVfaWQpICU+JSBzdW1tYXJpc2VfYWxsKG1lYW4sbmEucm0gPSBUUlVFKQpzM19kb3duXzIwIDwtIHMzX2Rvd25fMjAgJT4lIHNlbGVjdCgtZ2VuZV9pZCkgJT4lIHN1bW1hcmlzZV9hbGwobWVhbixuYS5ybSA9IFRSVUUpCmBgYAoKCmBgYHtyfQpzMV9kb3duXzIwCnMyX2Rvd25fMjAKczNfZG93bl8yMApgYGAKClN1bW1hcml6aW5nIDJrYiB1cHN0cmVhbSBnZW5lIHJlZ2lvbiBwZXIgc3RhZ2UKCmBgYHtyfQojQ2FsbCB3aW5kb3ctYmFzZWQgbWV0aHlsYXRpb24gZmlsZXMgcGVyIHN0YWdlCnMxX3VwXzIwIDwtIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS93ZWkvZ2Vub21lL3VwL25vc3RyYW5kL1MxX3VwMmtiX3dpbjIwXzVfc3VtIiwgaGVhZGVyID0gRiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHMxX3VwXzIwKSA8LSBjKCJnZW5lX2lkIiwid2luZG93IiwiY3BnX2NvdW50IiwibWV0aHlsYXRpb24iKQpzMl91cF8yMCA8LSByZWFkLnRhYmxlKCIvZHJpdmVzL3NzZDEvd2VpL2dlbm9tZS91cC9ub3N0cmFuZC9TMl91cDJrYl93aW4yMF81X3N1bSIsIGhlYWRlciA9IEYsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhzMl91cF8yMCkgPC0gYygiZ2VuZV9pZCIsIndpbmRvdyIsImNwZ19jb3VudCIsIm1ldGh5bGF0aW9uIikKczNfdXBfMjAgPC0gcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL3dlaS9nZW5vbWUvdXAvbm9zdHJhbmQvUzNfdXAya2Jfd2luMjBfNV9zdW0iLCBoZWFkZXIgPSBGLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKY29sbmFtZXMoczNfdXBfMjApIDwtIGMoImdlbmVfaWQiLCJ3aW5kb3ciLCJjcGdfY291bnQiLCJtZXRoeWxhdGlvbiIpCgojIFN1bW1hcmlzZSBmaWxlcywgZXN0aW1hdGluZyB3aW5kb3ctYmFzZWQgYXZlcmFnZSBtZXRoeWxhdGlvbiBhY3Jvc3MgZ2VuZXMKczFfdXBfMjAgPC0gczFfdXBfMjAgJT4lCiAgbXV0YXRlKHdpbmRvdz1wYXN0ZTAoInciLHdpbmRvdykpICU+JSBwaXZvdF93aWRlcigtIGNwZ19jb3VudCxuYW1lc19mcm9tID0gd2luZG93LHZhbHVlc19mcm9tID0gbWV0aHlsYXRpb24pIApzMV91cF8yMCA8LSBzMV91cF8yMFssYygiZ2VuZV9pZCIscGFzdGUwKCJ3IixzZXEoMToyMCkpKV0KCnMyX3VwXzIwIDwtIHMyX3VwXzIwICAlPiUKICBtdXRhdGUod2luZG93PXBhc3RlMCgidyIsd2luZG93KSkgJT4lIHBpdm90X3dpZGVyKC0gY3BnX2NvdW50LG5hbWVzX2Zyb20gPSB3aW5kb3csdmFsdWVzX2Zyb20gPSBtZXRoeWxhdGlvbikgCnMyX3VwXzIwIDwtIHMyX3VwXzIwWyxjKCJnZW5lX2lkIixwYXN0ZTAoInciLHNlcSgxOjIwKSkpXQoKczNfdXBfMjAgPC0gczNfdXBfMjAgICU+JQogIG11dGF0ZSh3aW5kb3c9cGFzdGUwKCJ3Iix3aW5kb3cpKSAlPiUgcGl2b3Rfd2lkZXIoLSBjcGdfY291bnQsbmFtZXNfZnJvbSA9IHdpbmRvdyx2YWx1ZXNfZnJvbSA9IG1ldGh5bGF0aW9uKSAKczNfdXBfMjAgPC0gczNfdXBfMjBbLGMoImdlbmVfaWQiLHBhc3RlMCgidyIsc2VxKDE6MjApKSldCgojIEZpbmFsIGRhdGEKczFfdXBfMjAgPC0gczFfdXBfMjAgJT4lIHNlbGVjdCgtZ2VuZV9pZCkgJT4lIHN1bW1hcmlzZV9hbGwobWVhbixuYS5ybSA9IFRSVUUpCnMyX3VwXzIwIDwtIHMyX3VwXzIwICU+JSBzZWxlY3QoLWdlbmVfaWQpICU+JSBzdW1tYXJpc2VfYWxsKG1lYW4sbmEucm0gPSBUUlVFKQpzM191cF8yMCA8LSBzM191cF8yMCAlPiUgc2VsZWN0KC1nZW5lX2lkKSAlPiUgc3VtbWFyaXNlX2FsbChtZWFuLG5hLnJtID0gVFJVRSkKYGBgCgoKYGBge3J9CnMxX3VwXzIwCnMyX3VwXzIwCnMzX3VwXzIwCmBgYAoKTWVyZ2UgdXBzdHJlYW0sIGdlbmVfYm9keSBhbmQgZG93bnN0cmVhbSBhdmVyYWdlIG1ldGh5bGF0aW9uIGRhdGEKCmBgYHtyfQp1cF9nZW5lX2Rvd25fbWV0aCA8LSByYmluZCgKY2JpbmQoczFfdXBfMjAsczFfZ2VuZWJvZHlfdzEwMCxzMV9kb3duXzIwKSwKY2JpbmQoczJfdXBfMjAsczJfZ2VuZWJvZHlfdzEwMCxzMl9kb3duXzIwKSwKY2JpbmQoczNfdXBfMjAsczNfZ2VuZWJvZHlfdzEwMCxzM19kb3duXzIwKSkgIyU+JSBtdXRhdGUoc3RhZ2U9IGMoIlMxIiwiUzIiLCJTMyIpKQpjb2xuYW1lcyh1cF9nZW5lX2Rvd25fbWV0aCkgPC0gcGFzdGUwKCJ3IixzZXEoMToxNDApKQp1cF9nZW5lX2Rvd25fbWV0aCA8LSB1cF9nZW5lX2Rvd25fbWV0aCAlPiUgZHBseXI6Om11dGF0ZShzdGFnZT0gYygiUzEiLCJTMiIsIlMzIikpICU+JSBwaXZvdF9sb25nZXIoLXN0YWdlKQp1cF9nZW5lX2Rvd25fbWV0aApgYGAKClBsb3QKCmBgYHtyfQojc2V0d2QoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvIikKZ2VuZUJvZHlfdXBEb3duX21ldGhfcGxvdCA8LXVwX2dlbmVfZG93bl9tZXRoICU+JSAKICBtdXRhdGUoc3RhZ2U9ZmFjdG9yKHN0YWdlLCBsZXZlbHM9IGMoIlMxIiwiUzIiLCJTMyIpKSwKICAgICAgICAgbmFtZT1mYWN0b3IobmFtZSxsZXZlbHMgPXBhc3RlMCgidyIsc2VxKDE6MTQwKSkpKSAlPiUKICBnZ3Bsb3QoYWVzKHk9dmFsdWUgLHg9bmFtZSwgZ3JvdXA9c3RhZ2UsY29sb3I9c3RhZ2UpKSArIGdlb21fbGluZShzaXplPTAuOCkgICsKICB4bGFiKCIiKSArICB5bGFiKCJNZXRoeWxhdGlvbiAoJSkiKSArCiAgZ2d0aXRsZSgiIikgKwogIHNjYWxlX3hfZGlzY3JldGUoYnJlYWtzID0gYygndzgnLCd3MjAnLCd3NzAnLCd3MTIwJywndzEzNScpLCAKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIlVwc3RyZWFtIiwiVFNTIiwiR2VuZSBib2R5IiwiVEVTIiwiRG93bnN0cmVhbSIpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIm9yYW5nZTIiLCJtaXN0eXJvc2U0IiwibWFyb29uIiksCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIlMxIiwiUzIiLCJTMyIpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwLTkgaHJzIiwiMTEtMTIgaHJzIiwiMjQtNjAgaHJzIikpICsgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXI9TkEpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0gInRyYW5zcGFyZW50IiwgY29sb3VyPU5BKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjg3LDAuNjUpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDE1LCJwdCIpLAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLHZqdXN0ID0gMS4xNSxhbmdsZT0zMCxoanVzPTEuMiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpCgojdGlmZigiZ2VuZUJvZHlfdXBEb3duX21ldGgudGlmZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMi41LCB1bml0cyA9ICJpbiIscmVzID0gNDAwLGNvbXByZXNzaW9uID0gImx6dyIpCmdlbmVCb2R5X3VwRG93bl9tZXRoX3Bsb3QKI2Rldi5vZmYoKQpgYGAKCiMgRXhvbi1pbnRyb24gbWV0aHlsYXRpb24gbGV2ZWwgLSBGaWcgNUQKRWFjaCBleG9uIHdhcyBzcGxpdCBpbiAzMCB3aW5kb3dzLCB3aGlsZSBlYWNoIGludHJvbiB3YXMgc3BsaXQgaW4gODAgd2luZG93cy4gRm9yIGVhY2ggd2luZG93cywgdGhlIGF2ZXJhZ2UgQ3BHIG1ldGh5bGF0aW9uIHdhcyBlc3RpbWF0ZWQuIFRoZSBncmFwaCByZXByZXNlbnQgdGhlIGF2ZXJhZ2UgbWV0aHlsYXRpb24gcGVyIHdpbmRvdyBhY3Jvc3MgZ2VuZXMsIHVzaW5nIG9ubHkgdGhlIGZpcnN0IGZvdXIgZXhvbnMgYW5kIGludHJvbnMuCgpFeG9uIG1ldGh5bGF0aW9uIAoKYGBge3J9CiNDYWxsIHdpbmRvdy1iYXNlZCBtZXRoeWxhdGlvbiBmaWxlcyBwZXIgc3RhZ2UKczFfZXhvbl8zMCA8LSByZWFkLnRhYmxlKCIvZHJpdmVzL3NzZDEvd2VpL2dlbm9tZS9leG9uL25vc3RyYW5kL1MxX2V4b25fbW9kaWZ5X3dpbjMwXzVfc3VtIiwgaGVhZGVyID0gRiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHMxX2V4b25fMzApIDwtIGMoImdlbmVfaWQiLCJleG9uX24iLCJ3aW5kb3ciLCJjcGdfY291bnQiLCJtZXRoeWxhdGlvbiIpCnMyX2V4b25fMzAgPC0gcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL3dlaS9nZW5vbWUvZXhvbi9ub3N0cmFuZC9TMl9leG9uX21vZGlmeV93aW4zMF81X3N1bSIsIGhlYWRlciA9IEYsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhzMl9leG9uXzMwKSA8LSBjKCJnZW5lX2lkIiwiZXhvbl9uIiwid2luZG93IiwiY3BnX2NvdW50IiwibWV0aHlsYXRpb24iKQpzM19leG9uXzMwIDwtIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS93ZWkvZ2Vub21lL2V4b24vbm9zdHJhbmQvUzNfZXhvbl9tb2RpZnlfd2luMzBfNV9zdW0iLCBoZWFkZXIgPSBGLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKY29sbmFtZXMoczNfZXhvbl8zMCkgPC0gYygiZ2VuZV9pZCIsImV4b25fbiIsIndpbmRvdyIsImNwZ19jb3VudCIsIm1ldGh5bGF0aW9uIikKCmBgYAoKYGBge3J9CnMxX2V4b25fMzAgJT4lIGhlYWQoKQpgYGAKCgpgYGB7cn0KI1N1bW1hcmlzZWQgaW50cm9uIG1ldGh5bGF0aW9uIC0gU3RhZ2UxCmV4b25fbWV0aHlfbGlzdF9zMSA9IGxpc3QoKQpmb3IgKGkgaW4gMTo0KSB7ICMgT25seSBleHRyYWN0IGRhdGEgZm9yIGZpcnN0IDQgaW50cm9ucwogIHRlbXBfZGYgPC0gczFfZXhvbl8zMCAlPiUgbXV0YXRlKHdpbmRvdz1wYXN0ZTAoInciLHdpbmRvdykpICU+JSBmaWx0ZXIoZXhvbl9uID09IGkpICU+JSAKICAgIHBpdm90X3dpZGVyKC0gY3BnX2NvdW50LG5hbWVzX2Zyb20gPSB3aW5kb3csdmFsdWVzX2Zyb20gPSBtZXRoeWxhdGlvbikgJT4lIHNlbGVjdCgtZXhvbl9uKQogIHRlbXBfZGYgPC0gdGVtcF9kZlssYygiZ2VuZV9pZCIscGFzdGUwKCJ3IixzZXEoMTozMCkpKV0KICB0ZW1wX2RmIDwtIHRlbXBfZGYgJT4lIHNlbGVjdCgtZ2VuZV9pZCkgJT4lIHN1bW1hcmlzZV9hbGwobWVhbixuYS5ybSA9IFRSVUUpCgpleG9uX21ldGh5X2xpc3RfczFbW2ldXSA8LSB0ZW1wX2RmCn0KCiNTdW1tYXJpc2VkIGludHJvbiBtZXRoeWxhdGlvbiAtIFN0YWdlMgpleG9uX21ldGh5X2xpc3RfczIgPSBsaXN0KCkKZm9yIChpIGluIDE6NCkgeyAjIE9ubHkgZXh0cmFjdCBkYXRhIGZvciBmaXJzdCA0IGludHJvbnMKICB0ZW1wX2RmIDwtIHMyX2V4b25fMzAgJT4lIG11dGF0ZSh3aW5kb3c9cGFzdGUwKCJ3Iix3aW5kb3cpKSAlPiUgZmlsdGVyKGV4b25fbiA9PSBpKSAlPiUgCiAgICBwaXZvdF93aWRlcigtIGNwZ19jb3VudCxuYW1lc19mcm9tID0gd2luZG93LHZhbHVlc19mcm9tID0gbWV0aHlsYXRpb24pICU+JSBzZWxlY3QoLWV4b25fbikKICB0ZW1wX2RmIDwtIHRlbXBfZGZbLGMoImdlbmVfaWQiLHBhc3RlMCgidyIsc2VxKDE6MzApKSldCiAgdGVtcF9kZiA8LSB0ZW1wX2RmICU+JSBzZWxlY3QoLWdlbmVfaWQpICU+JSBzdW1tYXJpc2VfYWxsKG1lYW4sbmEucm0gPSBUUlVFKQoKZXhvbl9tZXRoeV9saXN0X3MyW1tpXV0gPC0gdGVtcF9kZgp9CgojU3VtbWFyaXNlZCBpbnRyb24gbWV0aHlsYXRpb24gLSBTdGFnZTIKZXhvbl9tZXRoeV9saXN0X3MzID0gbGlzdCgpCmZvciAoaSBpbiAxOjQpIHsgIyBPbmx5IGV4dHJhY3QgZGF0YSBmb3IgZmlyc3QgNCBpbnRyb25zCiAgdGVtcF9kZiA8LSBzM19leG9uXzMwICU+JSBtdXRhdGUod2luZG93PXBhc3RlMCgidyIsd2luZG93KSkgJT4lIGZpbHRlcihleG9uX24gPT0gaSkgJT4lIAogICAgcGl2b3Rfd2lkZXIoLSBjcGdfY291bnQsbmFtZXNfZnJvbSA9IHdpbmRvdyx2YWx1ZXNfZnJvbSA9IG1ldGh5bGF0aW9uKSAlPiUgc2VsZWN0KC1leG9uX24pCiAgdGVtcF9kZiA8LSB0ZW1wX2RmWyxjKCJnZW5lX2lkIixwYXN0ZTAoInciLHNlcSgxOjMwKSkpXQogIHRlbXBfZGYgPC0gdGVtcF9kZiAlPiUgc2VsZWN0KC1nZW5lX2lkKSAlPiUgc3VtbWFyaXNlX2FsbChtZWFuLG5hLnJtID0gVFJVRSkKCmV4b25fbWV0aHlfbGlzdF9zM1tbaV1dIDwtIHRlbXBfZGYKfQpgYGAKCmBgYHtyfQpleG9uX21ldGh5X2xpc3RfczEKYGBgCgoKSW50cm9uIG1ldGh5bGF0aW9uIAoKYGBge3J9CiNDYWxsIHdpbmRvdy1iYXNlZCBtZXRoeWxhdGlvbiBmaWxlcyBwZXIgc3RhZ2UKczFfaW50cm9uXzgwIDwtIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS93ZWkvZ2Vub21lL2ludHJvbi9ub3N0cmFuZC9TMV9pbnRyb25fbW9kaWZ5X3dpbjgwXzVfc3VtIiwgaGVhZGVyID0gRiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHMxX2ludHJvbl84MCkgPC0gYygiZ2VuZV9pZCIsImludHJvbl9uIiwid2luZG93IiwiY3BnX2NvdW50IiwibWV0aHlsYXRpb24iKQpzMl9pbnRyb25fODAgPC0gcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL3dlaS9nZW5vbWUvaW50cm9uL25vc3RyYW5kL1MyX2ludHJvbl9tb2RpZnlfd2luODBfNV9zdW0iLCBoZWFkZXIgPSBGLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKY29sbmFtZXMoczJfaW50cm9uXzgwKSA8LSBjKCJnZW5lX2lkIiwiaW50cm9uX24iLCJ3aW5kb3ciLCJjcGdfY291bnQiLCJtZXRoeWxhdGlvbiIpCnMzX2ludHJvbl84MCA8LSByZWFkLnRhYmxlKCIvZHJpdmVzL3NzZDEvd2VpL2dlbm9tZS9pbnRyb24vbm9zdHJhbmQvUzNfaW50cm9uX21vZGlmeV93aW44MF81X3N1bSIsIGhlYWRlciA9IEYsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhzM19pbnRyb25fODApIDwtIGMoImdlbmVfaWQiLCJpbnRyb25fbiIsIndpbmRvdyIsImNwZ19jb3VudCIsIm1ldGh5bGF0aW9uIikKCmBgYAoKYGBge3J9CnMxX2ludHJvbl84MCAlPiUgaGVhZCgpCmBgYAoKCmBgYHtyfQojU3VtbWFyaXNlZCBpbnRyb24gbWV0aHlsYXRpb24gLSBTdGFnZTEKaW50cm9uX21ldGh5X2xpc3RfczEgPSBsaXN0KCkKZm9yIChpIGluIDE6NCkgeyAjIE9ubHkgZXh0cmFjdCBkYXRhIGZvciBmaXJzdCA0IGludHJvbnMKICB0ZW1wX2RmIDwtIHMxX2ludHJvbl84MCAlPiUgbXV0YXRlKHdpbmRvdz1wYXN0ZTAoInciLHdpbmRvdykpICU+JSBmaWx0ZXIoaW50cm9uX24gPT0gaSkgJT4lIAogICAgcGl2b3Rfd2lkZXIoLSBjcGdfY291bnQsbmFtZXNfZnJvbSA9IHdpbmRvdyx2YWx1ZXNfZnJvbSA9IG1ldGh5bGF0aW9uKSAlPiUgc2VsZWN0KC1pbnRyb25fbikKICB0ZW1wX2RmIDwtIHRlbXBfZGZbLGMoImdlbmVfaWQiLHBhc3RlMCgidyIsc2VxKDE6ODApKSldCiAgdGVtcF9kZiA8LSB0ZW1wX2RmICU+JSBzZWxlY3QoLWdlbmVfaWQpICU+JSBzdW1tYXJpc2VfYWxsKG1lYW4sbmEucm0gPSBUUlVFKQoKaW50cm9uX21ldGh5X2xpc3RfczFbW2ldXSA8LSB0ZW1wX2RmCn0KCiNTdW1tYXJpc2VkIGludHJvbiBtZXRoeWxhdGlvbiAtIFN0YWdlMgppbnRyb25fbWV0aHlfbGlzdF9zMiA9IGxpc3QoKQpmb3IgKGkgaW4gMTo0KSB7ICMgT25seSBleHRyYWN0IGRhdGEgZm9yIGZpcnN0IDQgaW50cm9ucwogIHRlbXBfZGYgPC0gczJfaW50cm9uXzgwICU+JSBtdXRhdGUod2luZG93PXBhc3RlMCgidyIsd2luZG93KSkgJT4lIGZpbHRlcihpbnRyb25fbiA9PSBpKSAlPiUgCiAgICBwaXZvdF93aWRlcigtIGNwZ19jb3VudCxuYW1lc19mcm9tID0gd2luZG93LHZhbHVlc19mcm9tID0gbWV0aHlsYXRpb24pICU+JSBzZWxlY3QoLWludHJvbl9uKQogIHRlbXBfZGYgPC0gdGVtcF9kZlssYygiZ2VuZV9pZCIscGFzdGUwKCJ3IixzZXEoMTo4MCkpKV0KICB0ZW1wX2RmIDwtIHRlbXBfZGYgJT4lIHNlbGVjdCgtZ2VuZV9pZCkgJT4lIHN1bW1hcmlzZV9hbGwobWVhbixuYS5ybSA9IFRSVUUpCgppbnRyb25fbWV0aHlfbGlzdF9zMltbaV1dIDwtIHRlbXBfZGYKfQoKI1N1bW1hcmlzZWQgaW50cm9uIG1ldGh5bGF0aW9uIC0gU3RhZ2UyCmludHJvbl9tZXRoeV9saXN0X3MzID0gbGlzdCgpCmZvciAoaSBpbiAxOjQpIHsgIyBPbmx5IGV4dHJhY3QgZGF0YSBmb3IgZmlyc3QgNCBpbnRyb25zCiAgdGVtcF9kZiA8LSBzM19pbnRyb25fODAgJT4lIG11dGF0ZSh3aW5kb3c9cGFzdGUwKCJ3Iix3aW5kb3cpKSAlPiUgZmlsdGVyKGludHJvbl9uID09IGkpICU+JSAKICAgIHBpdm90X3dpZGVyKC0gY3BnX2NvdW50LG5hbWVzX2Zyb20gPSB3aW5kb3csdmFsdWVzX2Zyb20gPSBtZXRoeWxhdGlvbikgJT4lIHNlbGVjdCgtaW50cm9uX24pCiAgdGVtcF9kZiA8LSB0ZW1wX2RmWyxjKCJnZW5lX2lkIixwYXN0ZTAoInciLHNlcSgxOjgwKSkpXQogIHRlbXBfZGYgPC0gdGVtcF9kZiAlPiUgc2VsZWN0KC1nZW5lX2lkKSAlPiUgc3VtbWFyaXNlX2FsbChtZWFuLG5hLnJtID0gVFJVRSkKCmludHJvbl9tZXRoeV9saXN0X3MzW1tpXV0gPC0gdGVtcF9kZgp9CmBgYAoKYGBge3J9CmludHJvbl9tZXRoeV9saXN0X3MxCmBgYAoKTWVyZ2UgZXhvbiBhbmQgaW50cm9uICBtZXRoeWxhdGlvbiBkYXRhCgpgYGB7cn0KZXhvbl9pbnRyb25fbWV0aCA8LSByYmluZChjYmluZChleG9uX21ldGh5X2xpc3RfczFbWzFdXSxpbnRyb25fbWV0aHlfbGlzdF9zMVtbMV1dLGV4b25fbWV0aHlfbGlzdF9zMVtbMl1dLGludHJvbl9tZXRoeV9saXN0X3MxW1syXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgZXhvbl9tZXRoeV9saXN0X3MxWzNdLGludHJvbl9tZXRoeV9saXN0X3MxW1szXV0sZXhvbl9tZXRoeV9saXN0X3MxW1s0XV0saW50cm9uX21ldGh5X2xpc3RfczFbWzRdXSksCiAgICAgICAgICAgICAgICAgICAgY2JpbmQoZXhvbl9tZXRoeV9saXN0X3MyW1sxXV0saW50cm9uX21ldGh5X2xpc3RfczJbWzFdXSxleG9uX21ldGh5X2xpc3RfczJbWzJdXSxpbnRyb25fbWV0aHlfbGlzdF9zMltbMl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgIGV4b25fbWV0aHlfbGlzdF9zMlszXSxpbnRyb25fbWV0aHlfbGlzdF9zMltbM11dLGV4b25fbWV0aHlfbGlzdF9zMltbNF1dLGludHJvbl9tZXRoeV9saXN0X3MyW1s0XV0pLAogICAgICAgICAgICAgICAgICAgIGNiaW5kKGV4b25fbWV0aHlfbGlzdF9zM1tbMV1dLGludHJvbl9tZXRoeV9saXN0X3MzW1sxXV0sZXhvbl9tZXRoeV9saXN0X3MzW1syXV0saW50cm9uX21ldGh5X2xpc3RfczNbWzJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBleG9uX21ldGh5X2xpc3RfczNbM10saW50cm9uX21ldGh5X2xpc3RfczNbWzNdXSxleG9uX21ldGh5X2xpc3RfczNbWzRdXSxpbnRyb25fbWV0aHlfbGlzdF9zM1tbNF1dKSkKCmNvbG5hbWVzKGV4b25faW50cm9uX21ldGgpIDwtIHBhc3RlMCgidyIsc2VxKDE6NDQwKSkKZXhvbl9pbnRyb25fbWV0aCA8LSBleG9uX2ludHJvbl9tZXRoICU+JSBkcGx5cjo6bXV0YXRlKHN0YWdlPSBjKCJTMSIsIlMyIiwiUzMiKSkgJT4lIHBpdm90X2xvbmdlcigtc3RhZ2UpCmV4b25faW50cm9uX21ldGgKYGBgCgoKYGBge3J9CiNzZXR3ZCgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy8iKQpleG9uSW50cm9uX21ldGhfcGxvdCA8LSBleG9uX2ludHJvbl9tZXRoICU+JSAKICBtdXRhdGUoc3RhZ2U9ZmFjdG9yKHN0YWdlLCBsZXZlbHM9IGMoIlMxIiwiUzIiLCJTMyIpKSwKICAgICAgICAgbmFtZT1mYWN0b3IobmFtZSxsZXZlbHMgPXBhc3RlMCgidyIsc2VxKDE6NDQwKSkpKSAlPiUKICBnZ3Bsb3QoYWVzKHk9dmFsdWUgLHg9bmFtZSwgZ3JvdXA9c3RhZ2UsY29sb3I9c3RhZ2UpKSArIGdlb21fbGluZShzaXplPTAuOCkgICsKICB4bGFiKCIiKSArICB5bGFiKCJNZXRoeWxhdGlvbiAoJSkiKSArIGdndGl0bGUoTlVMTCkgKwogIHNjYWxlX3hfZGlzY3JldGUoYnJlYWtzID0gcGFzdGUwKCd3JyxjKDEsMTUsMzAsNzAsMTEwLDEyNSwxNDAsMTgwLDIyMCwyMzUsMjUwLDI5MCwzMzAsMzQ1LDM2MCw0MDAsNDQwKSksIAogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiICIsIkV4b24xIiwiICIsIkludHJvbjEiLCIgIiwiRXhvbjIiLCIgIiwiSW50cm9uMiIsIiAiLCJFeG9uMyIsIiAiLCJJbnRyb24zIiwiICIsIkV4b240IiwiICIsIkludHJvbjQiLCIgIikpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygib3JhbmdlMiIsIm1pc3R5cm9zZTQiLCJtYXJvb24iKSwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygiUzEiLCJTMiIsIlMzIiksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAtOSBocnMiLCIxMS0xMiBocnMiLCIyNC02MCBocnMiKSkgKyB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91cj1OQSksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSAidHJhbnNwYXJlbnQiLCBjb2xvdXI9TkEpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50Iixjb2xvdXIgPSBOQSksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjg3LDAuNjUpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgxMiwicHQiKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NyksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCx2anVzdCA9IDAuNSksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpCgojdGlmZigiZXhvbkludHJvbl9tZXRoLnRpZmYiLCB3aWR0aCA9IDQsIGhlaWdodCA9IDIsIHVuaXRzID0gImluIixyZXMgPSA0MDAsY29tcHJlc3Npb24gPSAibHp3IikKZXhvbkludHJvbl9tZXRoX3Bsb3QKI2Rldi5vZmYoKQpgYGAKCiMgQW5hbHlzaXMgb2YgY292ZXJlZCBDcGdzLCAlb2YgbUNwZyBhbmQgbWV0aHlsYXRpb24gbGV2ZWwgZm9yIHdob2xlIGdlbmUgbGVuZ3RoIGFuZCBmaXJzdCAyNTAwIGJwCgpMb2FkIGRhdGEKCmBgYHtyfQojQ3BHcyBjb3ZlcmVkIGFsb25nIGZ1bGwgZ2VuZSBib2R5IC0gTnVtYmVyIGFuZCBtZXRoeWxhdGlvbiBhdmVyYWdlIHBlciBnZW5lCnMxX2NvdkNwR19jb3VudCA8LSAgcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy9zMV9jb3ZDcEdfY291bnQiLGhlYWRlciA9IEYsc2VwPSAiXHQiLCBzdHJpbmdzQXNGYWN0b3JzID0gRixuYS5zdHJpbmdzID0gJy4nKQpzMl9jb3ZDcEdfY291bnQgPC0gIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvczJfY292Q3BHX2NvdW50IixoZWFkZXIgPSBGLHNlcD0gIlx0Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsbmEuc3RyaW5ncyA9ICcuJykKczNfY292Q3BHX2NvdW50IDwtICByZWFkLnRhYmxlKCIvZHJpdmVzL3NzZDEvbWFudWVsL3BoYXcvMjAyMl9hbmFseXNpcy93Z2JzX2FuYWx5c2lzL3MzX2NvdkNwR19jb3VudCIsaGVhZGVyID0gRixzZXA9ICJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLG5hLnN0cmluZ3MgPSAnLicpCgojbUNwR3MgYWxvbmcgZnVsbCBnZW5lIGJvZHkgLSBOdW1iZXIgYW5kIG1ldGh5bGF0aW9uIGF2ZXJhZ2UgcGVyIGdlbmUKCnMxX21DcEdfY291bnQgPC0gIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvczFfbUNwR19jb3VudCIsaGVhZGVyID0gRixzZXA9ICJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLG5hLnN0cmluZ3MgPSAnLicpCnMyX21DcEdfY291bnQgPC0gIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvczJfbUNwR19jb3VudCIsaGVhZGVyID0gRixzZXA9ICJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLG5hLnN0cmluZ3MgPSAnLicpCnMzX21DcEdfY291bnQ8LSAgcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy9zM19tQ3BHX2NvdW50IixoZWFkZXIgPSBGLHNlcD0gIlx0Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsbmEuc3RyaW5ncyA9ICcuJykKCiNDcEdzIGNvdmVyZWQgYWxvbmcgNScgMjUwMCBicCBvZiBlYWNoIGdlbmUgLSBOdW1iZXIgYW5kIG1ldGh5bGF0aW9uIGF2ZXJhZ2UgcGVyIGdlbmUKczFfY292Q3BHX2NvdW50X2ZpcnN0MjUwMGJwIDwtICByZWFkLnRhYmxlKCIvZHJpdmVzL3NzZDEvbWFudWVsL3BoYXcvMjAyMl9hbmFseXNpcy93Z2JzX2FuYWx5c2lzL3MxX2NvdkNwR19jb3VudF9maXJzdDI1MDBicCIsaGVhZGVyID0gRixzZXA9ICJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLG5hLnN0cmluZ3MgPSAnLicpCnMyX2NvdkNwR19jb3VudF9maXJzdDI1MDBicCA8LSAgcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy9zMl9jb3ZDcEdfY291bnRfZmlyc3QyNTAwYnAiLGhlYWRlciA9IEYsc2VwPSAiXHQiLCBzdHJpbmdzQXNGYWN0b3JzID0gRixuYS5zdHJpbmdzID0gJy4nKQpzM19jb3ZDcEdfY291bnRfZmlyc3QyNTAwYnAgPC0gIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvczNfY292Q3BHX2NvdW50X2ZpcnN0MjUwMGJwIixoZWFkZXIgPSBGLHNlcD0gIlx0Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsbmEuc3RyaW5ncyA9ICcuJykKCiNtQ3BHcyBhbG9uZyA1JyAyNTAwIGJwIG9mIGVhY2ggZ2VuZSAtIE51bWJlciBhbmQgbWV0aHlsYXRpb24gYXZlcmFnZSBwZXIgZ2VuZQoKczFfbUNwR19jb3VudF9maXJzdDI1MDBicCA8LSAgcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy9zMV9tQ3BHX2NvdW50X2ZpcnN0MjUwMGJwIixoZWFkZXIgPSBGLHNlcD0gIlx0Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsbmEuc3RyaW5ncyA9ICcuJykKczJfbUNwR19jb3VudF9maXJzdDI1MDBicCA8LSAgcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy9zMl9tQ3BHX2NvdW50X2ZpcnN0MjUwMGJwIixoZWFkZXIgPSBGLHNlcD0gIlx0Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsbmEuc3RyaW5ncyA9ICcuJykKczNfbUNwR19jb3VudF9maXJzdDI1MDBicCA8LSAgcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy9zM19tQ3BHX2NvdW50X2ZpcnN0MjUwMGJwIixoZWFkZXIgPSBGLHNlcD0gIlx0Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsbmEuc3RyaW5ncyA9ICcuJykKCmBgYAoKTWVyZ2UgYW5kIHN1bW1hcmlzZSB3aG9sZSBnZW5lIGJvZHkgbWV0aHlsYXRpb24gZGF0YQoKYGBge3J9CmdlbmVCb2R5X2Z1bGxfbWV0aERhdGEgPC0gZHBseXI6OmJpbmRfcm93cyhsaXN0KHMxX2NvdkNwR19jb3VudCxzMl9jb3ZDcEdfY291bnQsczNfY292Q3BHX2NvdW50LHMxX21DcEdfY291bnQsczJfbUNwR19jb3VudCxzM19tQ3BHX2NvdW50KSwgLmlkID0gJ2NsYXNzJykgJT4lCiAgbXV0YXRlKGNsYXNzID0gcmVjb2RlKGNsYXNzLCAnMScgPSAnQ292OWhycycsICcyJyA9ICdDb3YxMmhycycsICczJyA9ICdDb3YyNGhycycsCiAgICAgICAgICAgICAgICAgICAgICAgICc0JyA9ICdtQ3BHOWhycycsICc1JyA9ICdtQ3BHMTJocnMnLCAnNicgPSAnbUNwRzI0aHJzJykpCmNvbG5hbWVzKGdlbmVCb2R5X2Z1bGxfbWV0aERhdGEpIDwtIGMoImNsYXNzIiwiZ2VuZSIsImdyb3VwIiwic3RyYW5kIiwiQ3BHX04iLCJtZXRoeWxhdGlvbiIpCmdlbmVCb2R5X2Z1bGxfbWV0aERhdGEgJT4lIGhlYWQoKQpgYGAKCkVzdGltYXRlIHBlcmNlbnRhZ2Ugb2YgZ2VuZSBib2R5IG1ldGh5bGF0ZWQgQ3BHcyAobUNwRykgLSBGaWcgNUUgbGVmdAoKYGBge3IgIGZpZzEsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSAxLjV9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUYsd2FybmluZz1GLGVjaG89VCkKI3NldHdkKCIvZHJpdmVzL3NzZDEvbWFudWVsL3BoYXcvMjAyMl9hbmFseXNpcy93Z2JzX2FuYWx5c2lzLyIpCmdlbmVCb2R5X21jcGdfcGVyYyA8LSBnZW5lQm9keV9mdWxsX21ldGhEYXRhICU+JSBzZWxlY3QoLWMoZ3JvdXAsc3RyYW5kKSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbT1jbGFzcyx2YWx1ZXNfZnJvbT0gYyhDcEdfTixtZXRoeWxhdGlvbikpICU+JSAKICBtdXRhdGUobUNwR19wZXJjOWhyPSAoQ3BHX05fbUNwRzlocnMvQ3BHX05fQ292OWhycykqMTAwLAogICAgICAgICBtQ3BHX3BlcmMxMmhyPSAoQ3BHX05fbUNwRzEyaHJzL0NwR19OX0NvdjEyaHJzKSoxMDAsCiAgICAgICAgIG1DcEdfcGVyYzI0aHI9IChDcEdfTl9tQ3BHMjRocnMvQ3BHX05fQ292MjRocnMpKjEwMCkgJT4lIHNlbGVjdChnZW5lLG1DcEdfcGVyYzlocixtQ3BHX3BlcmMxMmhyLG1DcEdfcGVyYzI0aHIpICU+JQogIG1lbHQoaWQudmFycz0iZ2VuZSIsdmFsdWUubmFtZSA9ICJtQ3BHX3BlcmMiKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXZhcmlhYmxlLHk9bUNwR19wZXJjLGZpbGw9dmFyaWFibGUpKSArIGdlb21fYm94cGxvdChvdXRsaWVyLmNvbG91ciA9ICJncmV5IixzaXplPTAuNCkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPSBjKCI5IGhycyIsIjExLTEyIGhycyIsIjI0LTYwIGhycyIpKSArCiAgc2NhbGVfeV9icmVhayhjKDQwLCA5NSksIHNjYWxlcyA9IDAuMSwgdGlja2xhYmVscz1jKDk1LCAxMDApKSArIHlsYWIoIkdlbmUgYm9keSBtQ3BHICUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIm9yYW5nZTIiLCJtaXN0eXJvc2U0IiwibWFyb29uIikpICsgCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsYW5nbGUgPTMwLHZqdXN0ID0gMC42NSxoanVzdCA9IDAuNyksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSxsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIGF4aXMudGV4dC54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLngudG9wID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsgeGxhYihOVUxMKSArIHlsYWIoTlVMTCkKCnN1cHByZXNzV2FybmluZ3MoZ3JpZC5hcnJhbmdlKGdlbmVCb2R5X21jcGdfcGVyYykpCgojdGlmZigiZ2VuZUJvZHlfbWNwZ19wZXJjLnRpZmYiLCB3aWR0aCA9IDEuNSwgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iLHJlcyA9IDQwMCxjb21wcmVzc2lvbiA9ICJsenciKQojZ2VuZUJvZHlfbWNwZ19wZXIKI2Rldi5vZmYoKQpgYGAKCkVzdGltYXRlIGdlbmUgYm9keSBtZXRoeWxhdGlvbiBsZXZlbCAtIEZpZyA1RiBsZWZ0CgpgYGB7ciAgZmlnMiwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDEuNX0KI3NldHdkKCIvZHJpdmVzL3NzZDEvbWFudWVsL3BoYXcvMjAyMl9hbmFseXNpcy93Z2JzX2FuYWx5c2lzLyIpCgpnZW5lQm9keV9tZXRoTGV2ZWxfYWxsIDwtIGdlbmVCb2R5X2Z1bGxfbWV0aERhdGEgJT4lIHNlbGVjdCgtYyhncm91cCxzdHJhbmQpKSAlPiUgI3NhbXBsZV9uKDYwMDApICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb209Y2xhc3MsdmFsdWVzX2Zyb209IGMoQ3BHX04sbWV0aHlsYXRpb24pKSAlPiUgCiAgc2VsZWN0KGdlbmUsbWV0aHlsYXRpb25fQ292OWhyczptZXRoeWxhdGlvbl9Db3YyNGhycykgJT4lCiAgbWVsdChpZC52YXJzPSJnZW5lIix2YWx1ZS5uYW1lID0gIk1ldGh5bGF0aW9uIikgJT4lICN0aWJibGUoKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXZhcmlhYmxlLHk9YXMubnVtZXJpYyhNZXRoeWxhdGlvbiksZmlsbD12YXJpYWJsZSkpICsgZ2VvbV9ib3hwbG90KCkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPSBjKCI5IGhycyIsIjExLTEyIGhycyIsIjI0LTYwIGhycyIpKSArICAKICBzY2FsZV95X2JyZWFrKGMoMzAsIDk1KSwgc2NhbGVzID0gMC4xLCB0aWNrbGFiZWxzPWMoOTUsIDEwMCkpICsgI3NjYWxlX3hfYnJlYWsoYyg0MCw5MCksIHNjYWxlcz0yKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIm9yYW5nZTIiLCJtaXN0eXJvc2U0IiwibWFyb29uIikpICsgCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsYW5nbGUgPTMwLHZqdXN0ID0gMC42NSxoanVzdCA9IDAuNyksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSxsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSxzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueC50b3AgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueC50b3AgPSBlbGVtZW50X2JsYW5rKCkpICsgeGxhYihOVUxMKSArIHlsYWIoIkdlbmUgYm9keSBtZXRoeWxhdGlvbiAlIikKCnN1cHByZXNzV2FybmluZ3MoZ3JpZC5hcnJhbmdlKGdlbmVCb2R5X21ldGhMZXZlbF9hbGwpKQojdGlmZigiZ2VuZUJvZHlfbWV0aExldmVsX2FsbC50aWZmIiwgd2lkdGggPSAxLjUsIGhlaWdodCA9IDMsIHVuaXRzID0gImluIixyZXMgPSA0MDAsY29tcHJlc3Npb24gPSAibHp3IikKI2dlbmVCb2R5X21ldGhMZXZlbF9hbGwKI2Rldi5vZmYoKQpgYGAKCgpNZXJnZSBhbmQgc3VtbWFyaXNlIGdlbmUgYm9keSAoZmlyc3QgMjUwMCBicCkgbWV0aHlsYXRpb24gZGF0YQogCmBgYHtyfQpnZW5lQm9keV91cDI1MDBfbWV0aERhdGEgPC0gZHBseXI6OmJpbmRfcm93cyhsaXN0KHMxX2NvdkNwR19jb3VudF9maXJzdDI1MDBicCxzMl9jb3ZDcEdfY291bnRfZmlyc3QyNTAwYnAsczNfY292Q3BHX2NvdW50X2ZpcnN0MjUwMGJwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMxX21DcEdfY291bnRfZmlyc3QyNTAwYnAsczJfbUNwR19jb3VudF9maXJzdDI1MDBicCxzM19tQ3BHX2NvdW50X2ZpcnN0MjUwMGJwKSwgLmlkID0gJ2NsYXNzJykgJT4lIAogIG11dGF0ZShjbGFzcyA9IHJlY29kZShjbGFzcywgJzEnID0gJ0NvdjlocnMnLCAnMicgPSAnQ292MTJocnMnLCAnMycgPSAnQ292MjRocnMnLAogICAgICAgICAgICAgICAgICAgICAgICAnNCcgPSAnbUNwRzlocnMnLCAnNScgPSAnbUNwRzEyaHJzJywgJzYnID0gJ21DcEcyNGhycycpKQpjb2xuYW1lcyhnZW5lQm9keV91cDI1MDBfbWV0aERhdGEpIDwtIGMoImNsYXNzIiwiZ2VuZSIsImdyb3VwIiwic3RyYW5kIiwiQ3BHX04iLCJtZXRoeWxhdGlvbiIpCmdlbmVCb2R5X3VwMjUwMF9tZXRoRGF0YSAlPiUgaGVhZCgpCmBgYAoKRXN0aW1hdGUgcGVyY2VudGFnZSBvZiBnZW5lIGJvZHkgKGZpcnN0IDI1MDAgYnApIG1ldGh5bGF0ZWQgQ3BHcyAobUNwRykgLSBGaWcgNUUgcmlnaHQKCmBgYHtyICBmaWczLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gMS41fQojc2V0d2QoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvIikKCmdlbmVCb2R5MjUwMF9tY3BnX3BlcmMgPC0gZ2VuZUJvZHlfdXAyNTAwX21ldGhEYXRhICU+JSAgc2VsZWN0KC1jKGdyb3VwLHN0cmFuZCkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb209Y2xhc3MsdmFsdWVzX2Zyb209IGMoQ3BHX04sbWV0aHlsYXRpb24pKSAlPiUgCiAgbXV0YXRlKG1DcEdfcGVyYzlocj0gKENwR19OX21DcEc5aHJzL0NwR19OX0NvdjlocnMpKjEwMCwKICAgICAgICAgbUNwR19wZXJjMTJocj0gKENwR19OX21DcEcxMmhycy9DcEdfTl9Db3YxMmhycykqMTAwLAogICAgICAgICBtQ3BHX3BlcmMyNGhyPSAoQ3BHX05fbUNwRzI0aHJzL0NwR19OX0NvdjI0aHJzKSoxMDApICU+JSBzZWxlY3QoZ2VuZSxtQ3BHX3BlcmM5aHIsbUNwR19wZXJjMTJocixtQ3BHX3BlcmMyNGhyKSAlPiUKICBtZWx0KGlkLnZhcnM9ImdlbmUiLHZhbHVlLm5hbWUgPSAibUNwR19wZXJjIikgJT4lIAogIGdncGxvdChhZXMoeD12YXJpYWJsZSx5PW1DcEdfcGVyYyxmaWxsPXZhcmlhYmxlKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXIgPSAiZ3JleSIsc2l6ZT0wLjQpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz0gYygiOSBocnMiLCIxMS0xMiBocnMiLCIyNC02MCBocnMiKSkgKwogIHNjYWxlX3lfYnJlYWsoYyg0MCwgOTUpLCBzY2FsZXMgPSAwLjEsIHRpY2tsYWJlbHM9Yyg5NSwgMTAwKSkgKyAjc2NhbGVfeF9icmVhayhjKDQwLDkwKSwgc2NhbGVzPTIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Yygib3JhbmdlMiIsIm1pc3R5cm9zZTQiLCJtYXJvb24iKSkgKyAKICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCxhbmdsZSA9MzAsdmp1c3QgPSAwLjY1LGhqdXN0ID0gMC43KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgICAgYXhpcy50ZXh0LngudG9wID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueC50b3AgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLngudG9wID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSxzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKyB4bGFiKE5VTEwpICsgeWxhYihOVUxMKQoKc3VwcHJlc3NXYXJuaW5ncyhncmlkLmFycmFuZ2UoZ2VuZUJvZHkyNTAwX21jcGdfcGVyYykpCgojdGlmZigiZ2VuZUJvZHkyNTAwX21jcGdfcGVyYy50aWZmIiwgd2lkdGggPSAxLjUsIGhlaWdodCA9IDMsIHVuaXRzID0gImluIixyZXMgPSA0MDAsY29tcHJlc3Npb24gPSAibHp3IikKI2dlbmVCb2R5MjUwMF9tY3BnX3BlcmMKI2Rldi5vZmYoKQpgYGAKCkVzdGltYXRlIGdlbmUgYm9keSAoZmlyc3QgMjUwMCBicCkgbWV0aHlsYXRpb24gbGV2ZWwgLSBGaWcgNUYgcmlnaHQKCmBgYHtyICBmaWc0LCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gMS41fQojc2V0d2QoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvIikKCmdlbmVCb2R5MjUwMF9tZXRoTGV2ZWxfYWxsIDwtIGdlbmVCb2R5X3VwMjUwMF9tZXRoRGF0YSAlPiUgc2VsZWN0KC1jKGdyb3VwLHN0cmFuZCkpICU+JSAjc2FtcGxlX24oNjAwMCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbT1jbGFzcyx2YWx1ZXNfZnJvbT0gYyhDcEdfTixtZXRoeWxhdGlvbikpICU+JSAKICBzZWxlY3QoZ2VuZSxtZXRoeWxhdGlvbl9Db3Y5aHJzOm1ldGh5bGF0aW9uX0NvdjI0aHJzKSAlPiUKICBtZWx0KGlkLnZhcnM9ImdlbmUiLHZhbHVlLm5hbWUgPSAiTWV0aHlsYXRpb24iKSAlPiUgI3RpYmJsZSgpICU+JSAKICBnZ3Bsb3QoYWVzKHg9dmFyaWFibGUseT1hcy5udW1lcmljKE1ldGh5bGF0aW9uKSxmaWxsPXZhcmlhYmxlKSkgKyBnZW9tX2JveHBsb3QoKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9IGMoIjkgaHJzIiwiMTEtMTIgaHJzIiwiMjQtNjAgaHJzIikpICsgIAogIHNjYWxlX3lfYnJlYWsoYygzMCwgOTUpLCBzY2FsZXMgPSAwLjEsIHRpY2tsYWJlbHM9Yyg5NSwgMTAwKSkgKyAjc2NhbGVfeF9icmVhayhjKDQwLDkwKSwgc2NhbGVzPTIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Yygib3JhbmdlMiIsIm1pc3R5cm9zZTQiLCJtYXJvb24iKSkgKyAKICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCxhbmdsZSA9MzAsdmp1c3QgPSAwLjY1LGhqdXN0ID0gMC43KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dC54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLngudG9wID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSkgKyB4bGFiKE5VTEwpICsgIHlsYWIoIkdlbmUgYm9keSBtZXRoeWxhdGlvbiAlIikKCnN1cHByZXNzV2FybmluZ3MoZ3JpZC5hcnJhbmdlKGdlbmVCb2R5MjUwMF9tZXRoTGV2ZWxfYWxsKSkKCiN0aWZmKCJnZW5lQm9keTI1MDBfbWV0aExldmVsX2FsbC50aWZmIiwgd2lkdGggPSAxLjUsIGhlaWdodCA9IDMsIHVuaXRzID0gImluIixyZXMgPSA0MDAsY29tcHJlc3Npb24gPSAibHp3IikKI2dlbmVCb2R5MjUwMF9tZXRoTGV2ZWxfYWxsCiNkZXYub2ZmKCkKYGBgCgpDb3ZlcmVkIENwR3MgcGVyIGdlbmUgLSBGaWcgUzEzRQoKYGBge3J9CiNzZXR3ZCgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy8iKQpnZW5lQm9keV9Db3ZfTl9hbGxfZGVuc2l0eSA8LSBnZW5lQm9keV9mdWxsX21ldGhEYXRhICU+JSBzZWxlY3QoLWMoZ3JvdXAsc3RyYW5kKSkgJT4lIAogIGZpbHRlcihncmVwbCgnQ292JyxjbGFzcykpICU+JSBtdXRhdGUoY2xhc3M9Z3N1YigiQ292IiwiIixjbGFzcykpICU+JSBtdXRhdGUoY2xhc3M9IGZhY3RvcihjbGFzcyxsZXZlbHMgPSBjKCI5aHJzIiwiMTJocnMiLCIyNGhycyIpKSkgJT4lCiAgZ2dwbG90KGFlcyh4PWFzLm51bWVyaWMoQ3BHX04pLGZpbGw9IGBjbGFzc2ApKSArIGdlb21fZGVuc2l0eShhbHBoYT0wLjUpICsgeGxpbShOQSw1MDApICsgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJvcmFuZ2UyIiwibWlzdHlyb3NlNCIsIm1hcm9vbiIpLGxhYmVscz0gYygiOSBocnMiLCIxMS0xMiBocnMiLCIyNC02MCBocnMiKSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSAxMCksIGNvbG9yPSJjaG9jb2xhdGU0IiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC41KSArIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsYW5nbGUgPTAsdmp1c3QgPSAwLjY1LGhqdXN0ID0gMC43KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLGxlZ2VuZC5wb3NpdGlvbj1jKDAuODUsMC44KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LngudG9wID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueC50b3AgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLngudG9wID0gZWxlbWVudF9ibGFuaygpKSArIHlsYWIoIkRlbnNpdHkiKSArIHhsYWIoIkNvdmVyZWQgQ3BHcyBwZXIgZ2VuZSIpCgojdGlmZigiZ2VuZUJvZHlfQ292X05fYWxsX2RlbnNpdHkudGlmZiIsIHdpZHRoID0gMy41LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIscmVzID0gNDAwLGNvbXByZXNzaW9uID0gImx6dyIpCmdlbmVCb2R5X0Nvdl9OX2FsbF9kZW5zaXR5CiNkZXYub2ZmKCkKYGBgCgoKUGF0dGVybiBvZiBnZW5lIG1ldGh5bGF0aW9uIHBlciBzdGFnZSAtIEZpZyA1RwoKYGBge3J9CiNzZXR3ZCgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvd2dic19hbmFseXNpcy8iKQpnZW5lQm9keV9tZXRoTGV2ZWxfYWxsX2RlbnNpdHkgPC0gZ2VuZUJvZHlfZnVsbF9tZXRoRGF0YSAlPiUgc2VsZWN0KC1jKGdyb3VwLHN0cmFuZCkpICU+JSAKICBmaWx0ZXIoZ3JlcGwoJ0NvdicsY2xhc3MpKSAlPiUgbXV0YXRlKGNsYXNzPWdzdWIoIkNvdiIsIiIsY2xhc3MpKSAlPiUgbXV0YXRlKGNsYXNzPSBmYWN0b3IoY2xhc3MsbGV2ZWxzID0gYygiOWhycyIsIjEyaHJzIiwiMjRocnMiKSkpICU+JQogIGdncGxvdChhZXMoeD1hcy5udW1lcmljKG1ldGh5bGF0aW9uKSxmaWxsPSBgY2xhc3NgKSkgKyBnZW9tX2RlbnNpdHkoYWxwaGE9MC41KSArCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gbG9nMTBfdHJhbnMoKSwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygwLDAuMDEsMC4xLDEsMywxMCwxMDApLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBsYWJlbF9udW1iZXIoYWNjdXJhY3kgPSAxKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIm9yYW5nZTIiLCJtaXN0eXJvc2U0IiwibWFyb29uIiksbGFiZWxzPSBjKCI5IGhycyIsIjExLTEyIGhycyIsIjI0LTYwIGhycyIpKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IDMpLCBjb2xvcj0iY2hvY29sYXRlNCIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuNSkgKyB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JyksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLGFuZ2xlID0wLHZqdXN0ID0gMC42NSxoanVzdCA9IDAuNyksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSxsZWdlbmQucG9zaXRpb249YygwLjE1LDAuOCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dC54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLngudG9wID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSkgKyB5bGFiKCJEZW5zaXR5IikgKyB4bGFiKCJHZW5lIG1ldGh5bGF0aW9uICUiKQoKCiN0aWZmKCJnZW5lQm9keV9tZXRoTGV2ZWxfYWxsX2RlbnNpdHkudGlmZiIsIHdpZHRoID0gMy41LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIscmVzID0gNDAwLGNvbXByZXNzaW9uID0gImx6dyIpCmdlbmVCb2R5X21ldGhMZXZlbF9hbGxfZGVuc2l0eQojZGV2Lm9mZigpCgpgYGAKIyBJZGVudGlmeSBhbmQgcXVhbnRpZnkgbWV0aHlsYXRlZCBnZW5lcyBwZXIgc3RhZ2UgIC0gRmlnIDVICgpgYGB7cn0Kc2V0d2QoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvIikKCm1ldGh5bGF0ZWRHZW5lc185aHJzIDwtIGdlbmVCb2R5X2Z1bGxfbWV0aERhdGEgJT4lIGZpbHRlcihjbGFzcyA9PSAiQ292OWhycyIgJiBDcEdfTiA+PSA1ICYgbWV0aHlsYXRpb24gPj0gMykgJT4lIHB1bGwoZ2VuZSkgCm1ldGh5bGF0ZWRHZW5lc18xMmhycyA8LSBnZW5lQm9keV9mdWxsX21ldGhEYXRhICU+JSBmaWx0ZXIoY2xhc3MgPT0gIkNvdjEyaHJzIiAmIENwR19OID49IDUgJiBtZXRoeWxhdGlvbiA+PSAzKSAlPiUgcHVsbChnZW5lKQptZXRoeWxhdGVkR2VuZXNfMjRocnMgPC0gZ2VuZUJvZHlfZnVsbF9tZXRoRGF0YSAlPiUgZmlsdGVyKGNsYXNzID09ICJDb3YyNGhycyIgJiBDcEdfTiA+PSA1ICYgbWV0aHlsYXRpb24gPj0gMykgJT4lIHB1bGwoZ2VuZSkKClJlZHVjZShpbnRlcnNlY3QsbGlzdChtZXRoeWxhdGVkR2VuZXNfOWhycyxtZXRoeWxhdGVkR2VuZXNfMTJocnMsbWV0aHlsYXRlZEdlbmVzXzI0aHJzKSkgJT4lIHVuaXF1ZSgpICU+JSBsZW5ndGgoKQoKI1Bsb3QgdmVubiBkaWFncmFtIGludGVyc2VjdGluZyBtZXRoeWxhdGVkIGdlbmVzIGFtb25nIHN0YWdlcwoKdmVubi5kaWFncmFtKAogIHggPSBsaXN0KG1ldGh5bGF0ZWRHZW5lc185aHJzLG1ldGh5bGF0ZWRHZW5lc18xMmhycyxtZXRoeWxhdGVkR2VuZXNfMjRocnMpLAogIGNhdGVnb3J5Lm5hbWVzID0gYygiOSBocnMiICwgIjExLTEyIGhycyIsIjI0LTYwIGhycyIpLAogIGZpbGVuYW1lID0gJ21ldGh5bGF0ZWRHZW5lc19vdmVybGFwcC50aWZmJywKICBoZWlnaHQgPSA0LCB3aWR0aCA9IDQsIHJlc29sdXRpb24gPSAzMDAsIGltYWdldHlwZSA9ICJ0aWZmIiwgCiAgdW5pdHMgPSAiaW4iLCBjb21wcmVzc2lvbiA9ICJsenciLCBmaWxsPSBjKCJvcmFuZ2UyIiwibWlzdHlyb3NlNCIsIm1hcm9vbiIgKSwKICBvdXRwdXQ9VCwgc2NhbGVkPVQscHJpbnQubW9kZT1jKCJyYXciLCJwZXJjZW50IikpCiAgCmBgYAoKVmlzdWFsaXNlIHZlbm4gZGlhZ3JhbWUgaW4gdGhlIG5vdGVib29rCgpgYGB7ciBmaWc1LCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gM30KcGx0ID0gdmVubi5kaWFncmFtKAogIHggPSBsaXN0KG1ldGh5bGF0ZWRHZW5lc185aHJzLG1ldGh5bGF0ZWRHZW5lc18xMmhycyxtZXRoeWxhdGVkR2VuZXNfMjRocnMpLAogIGNhdGVnb3J5Lm5hbWVzID0gYygiOSBocnMiICwgIjExLTEyIGhycyIsIjI0LTYwIGhycyIpLAogIGZpbGVuYW1lID0gTlVMTCwKICBoZWlnaHQgPSA0LCB3aWR0aCA9IDQsIHJlc29sdXRpb24gPSAzMDAsIGltYWdldHlwZSA9ICJ0aWZmIiwgCiAgdW5pdHMgPSAiaW4iLCBjb21wcmVzc2lvbiA9ICJsenciLCBmaWxsPSBjKCJvcmFuZ2UyIiwibWlzdHlyb3NlNCIsIm1hcm9vbiIgKSwKICBvdXRwdXQ9VCwgc2NhbGVkPVQscHJpbnQubW9kZT1jKCJyYXciLCJwZXJjZW50IikpCmdyaWQubmV3cGFnZSgpCmdyaWQ6OmdyaWQuZHJhdyhwbHQpCmBgYAojIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGdlbmUgbWV0aHlsYXRpb24gYW5kIGV4cHJlc3Npb24gbGV2ZWxzCkZvciBlYWNoIG1ldGh5bG9tZSBkYXRhc2V0ICgwLTksMTEtMTIgYW5kIDI0LTYwIGhycykgd2UgYW5hbHlzZWQgdGhlIGV4cHJlc3Npb24gbGV2ZWxzIGluIHRocmVlIHN1YnNlcXVlbnQgZW1icnlvbmljIHN0YWdlcy4gRXhwcmVzc2lvbiB3YXMgY2F0ZWdvcmlzZWQgYXMgYWJzZW50IChUUE0gPSAwKSwgbG93KFRQTSA8PTEpLCBtb2RlcmF0ZSAoVFBNIDw9NSkgYW5kIGhpZ2ggKFRQTSA+PTUpCgoKTWVyZ2UgTWV0aHlsIGFuZCBleHByZXNzaW9uIGRhdGEKCmBgYHtyfQplbWJyeW9fZXhvbkNvdW50c19wb2x5QV90cG0gPC0gcmVhZC50YWJsZSgiL2RyaXZlcy9zc2QxL21hbnVlbC9waGF3LzIwMjJfYW5hbHlzaXMvbXp0X2FuYWx5c2lzL2VtYnJ5b19leG9uQ291bnRzX3BvbHlBX3RwbS50eHQiLGhlYWRlciA9IFQsc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKGVtYnJ5b19leG9uQ291bnRzX3BvbHlBX3RwbSkgPC0gYygiZ2VuZV9pZCIsIjAtOWhycyIsIjExaHJzIiwiMTJocnMiLCIxNGhycyIsIjE2aHJzIiwiMjBocnMiLCIyNGhycyIsIjI0LTYwaHJzIikKCmVtYnJ5b19FeHBfTWV0aHlsX2RhdGEgPC0gbWVyZ2UoZW1icnlvX2V4b25Db3VudHNfcG9seUFfdHBtLApnZW5lQm9keV9mdWxsX21ldGhEYXRhICU+JSBzZWxlY3QoLWMoZ3JvdXAsc3RyYW5kKSkgJT4lIAogIGZpbHRlcihncmVwbCgnQ292JyxjbGFzcykpICU+JSBtdXRhdGUoY2xhc3M9Z3N1YigiQ292IiwiIixjbGFzcykpICU+JSAKICBtdXRhdGUoY2xhc3M9IGZhY3RvcihjbGFzcyxsZXZlbHMgPSBjKCI5aHJzIiwiMTJocnMiLCIyNGhycyIpKSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb209Y2xhc3MsdmFsdWVzX2Zyb209IGMoQ3BHX04sbWV0aHlsYXRpb24pKSxieS54ID0gImdlbmVfaWQiLGJ5LnkgPSAiZ2VuZSIpCgplbWJyeW9fRXhwX01ldGh5bF9kYXRhCmBgYAoKR2VuZSBleHByZXNzaW9uIGF0IDExLCAxMiBhbmQgMTMtMTQgaHJzIGVtYnJ5b3MgYmFzZWQgb24gbWV0aHlsYXRpb24gZnJvbSAwLTk6MTUgaHJzIGVtYnJ5b3MgLSBGaWcgNUksIGxlZnQKCgpgYGB7ciBmaWc2LCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gMi41fQpnZXRfbXlfY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg2LCAiRGFyazIiKSkKbXljb2xvcnMgPC0gZ2V0X215X2NvbG9ycyg4KQoKIyBDb3JyZWxhdGUgOWhycyBtZXRoeWxhdGlvbiB3aXRoIGFsbCBleHByZXNzaW9uIHRpbWVwb2ludHMgLSBCb3hwbG90cwpFeHBNZXRoeWxfY29yXzlocnMgPC0gZW1icnlvX0V4cF9NZXRoeWxfZGF0YSAlPiUgc2VsZWN0KC1jKGBDcEdfTl85aHJzYDpgQ3BHX05fMjRocnNgLGBtZXRoeWxhdGlvbl8xMmhyc2AsYG1ldGh5bGF0aW9uXzI0aHJzYCkpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKGdlbmVfaWQsbWV0aHlsYXRpb25fOWhycyksbmFtZXNfdG8gPSAiZXhwX3N0YWdlIix2YWx1ZXNfdG89ImV4cF9jb3VudCIpICU+JSAKICBtdXRhdGUoZXhwX3N0YWdlPWZhY3RvcihleHBfc3RhZ2UsbGV2ZWxzID0gYygiZ2VuZV9pZCIsIjAtOWhycyIsIjExaHJzIiwiMTJocnMiLCIxNGhycyIsIjE2aHJzIiwiMjBocnMiLCIyNGhycyIsIjI0LTYwaHJzIikpKSAlPiUKICBtdXRhdGUoZXhwX2NhdD0gaWZlbHNlKGV4cF9jb3VudCA9PSAwLCAiMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoYmV0d2VlbihleHBfY291bnQsMCwxKSwi4omkIDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShiZXR3ZWVuKGV4cF9jb3VudCwxLDUpLCLiiaQgNSIsIuKJpSA1IikpKSkgJT4lIAogIGZpbHRlcihleHBfc3RhZ2UgJWluJSBjKCIxMWhycyIsIjEyaHJzIiwiMTRocnMiKSkgJT4lICAjIGZpbHRlcihnZW5lX2lkICVpbiUgbWV0aHlsYXRlZEdlbmVzXzlocnMpICU+JQogIG11dGF0ZShleHBfY2F0PWZhY3RvcihleHBfY2F0LGxldmVscyA9IGMoIjAiLCLiiaQgMSIsIuKJpCA1Iiwi4omlIDUiKSkpICU+JQogIGdncGxvdChhZXMoZmlsbD1leHBfc3RhZ2UseD1leHBfY2F0LHk9bWV0aHlsYXRpb25fOWhycykpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyID0gImdyZXkiLG91dGxpZXIuc2l6ZSA9IDAuNCxhbHBoYT0wLjYpKwogIHlsaW0oTkEsMjApICsgIyB0byBwcmludCBpbiBub3RlYm9vawogICNzY2FsZV95X2JyZWFrKGMoMjAsIDk1KSwgc2NhbGVzID0gMC4wMSwgdGlja2xhYmVscz1jKDk1LCAxMDApKSArICMgdG8gc2F2ZSBmaWd1cmUKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZmlyZWJyaWNrMyIsImRhcmtzbGF0ZWdyYXkiLCJkb2RnZXJibHVlIikpICsgCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDMpLCBjb2xvcj0iY2hvY29sYXRlNCIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuNSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAzKSwgY29sb3I9ImNob2NvbGF0ZTQiLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjUpICsKICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC41LCAnY20nKSxsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0idG9wIixsZWdlbmQuanVzdGlmaWNhdGlvbj0icmlnaHQiLGxlZ2VuZC5tYXJnaW49bWFyZ2luKDAsMCwwLDApLCNsZWdlbmQuYm94Lm1hcmdpbj1tYXJnaW4oLTIwLC0xMDAsLTEwLC0xMCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLGFuZ2xlID0wLHZqdXN0ID0gMC42NSxoanVzdCA9IDAuNyksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dC54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSxheGlzLnRpY2tzLngudG9wID0gZWxlbWVudF9ibGFuaygpLGF4aXMubGluZS54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB5bGFiKCJHZW5lIG1ldGh5bGF0aW9uICUgLSA5aHJzIikgICsgeGxhYihOVUxMKSAKCiN0aWZmKCJFeHBNZXRoeWxfY29yXzlocnMudGlmZiIsIHdpZHRoID0gMi41LCBoZWlnaHQgPSAzLjUsIHVuaXRzID0gImluIixyZXMgPSAzMDAsY29tcHJlc3Npb24gPSAibHp3IikKI0V4cE1ldGh5bF9jb3JfOWhycwojZGV2Lm9mZigpCnN1cHByZXNzV2FybmluZ3MoZ3JpZC5hcnJhbmdlKEV4cE1ldGh5bF9jb3JfOWhycykpCmBgYApHZW5lIGV4cHJlc3Npb24gYXQgMTIsIDE0IGFuZCAxNiBocnMgZW1icnlvcyBiYXNlZCBvbiBtZXRoeWxhdGlvbiBmcm9tIDExLTEyIGhycyBlbWJyeW9zIC0gRmlnIDVJLCBtaWRkbGUKCmBgYHtyIGZpZzcsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSAyLjV9CkV4cE1ldGh5bF9jb3JfMTJocnMgPC0gZW1icnlvX0V4cF9NZXRoeWxfZGF0YSAlPiUgc2VsZWN0KC1jKGBDcEdfTl85aHJzYDpgQ3BHX05fMjRocnNgLGBtZXRoeWxhdGlvbl85aHJzYCxgbWV0aHlsYXRpb25fMjRocnNgKSkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gLWMoZ2VuZV9pZCxtZXRoeWxhdGlvbl8xMmhycyksbmFtZXNfdG8gPSAiZXhwX3N0YWdlIix2YWx1ZXNfdG89ImV4cF9jb3VudCIpICU+JSAKICBtdXRhdGUoZXhwX3N0YWdlPWZhY3RvcihleHBfc3RhZ2UsbGV2ZWxzID0gYygiZ2VuZV9pZCIsIjAtOWhycyIsIjExaHJzIiwiMTJocnMiLCIxNGhycyIsIjE2aHJzIiwiMjBocnMiLCIyNGhycyIsIjI0LTYwaHJzIikpKSAlPiUKICBtdXRhdGUoZXhwX2NhdD0gaWZlbHNlKGV4cF9jb3VudCA9PSAwLCAiMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoYmV0d2VlbihleHBfY291bnQsMCwxKSwi4omkIDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShiZXR3ZWVuKGV4cF9jb3VudCwxLDUpLCLiiaQgNSIsIuKJpSA1IikpKSkgJT4lIAogIGZpbHRlcihleHBfc3RhZ2UgJWluJSBjKCIxMmhycyIsIjE0aHJzIiwiMTZocnMiKSkgJT4lCiAgbXV0YXRlKGV4cF9jYXQ9ZmFjdG9yKGV4cF9jYXQsbGV2ZWxzID0gYygiMCIsIuKJpCAxIiwi4omkIDUiLCLiiaUgNSIpKSkgJT4lCiAgZ2dwbG90KGFlcyhmaWxsPWV4cF9zdGFnZSx4PWV4cF9jYXQseT1tZXRoeWxhdGlvbl8xMmhycykpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyID0gImdyZXkiLG91dGxpZXIuc2l6ZSA9IDAuNCxhbHBoYT0wLjYpKwogIHlsaW0oTkEsMjApICsgIyB0byBwcmludCBpbiBub3RlYm9vawogICNzY2FsZV95X2JyZWFrKGMoMjAsIDk1KSwgc2NhbGVzID0gMC4wMSwgdGlja2xhYmVscz1jKDk1LCAxMDApKSArICMgdG8gc2F2ZSBmaWd1cmUKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZGFya3NsYXRlZ3JheSIsImRvZGdlcmJsdWUiLCJkYXJrb3JhbmdlMSIpKSArICAjc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAzKSwgY29sb3I9ImNob2NvbGF0ZTQiLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjUpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMyksIGNvbG9yPSJjaG9jb2xhdGU0IiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC41KSArCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSxsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgJ2NtJyksbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBsZWdlbmQucG9zaXRpb249InRvcCIsbGVnZW5kLmp1c3RpZmljYXRpb249InJpZ2h0IixsZWdlbmQubWFyZ2luPW1hcmdpbigwLDAsMCwwKSwjbGVnZW5kLmJveC5tYXJnaW49bWFyZ2luKC0yMCwtMTAwLC0xMCwtMTApLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCxhbmdsZSA9MCx2anVzdCA9IDAuNjUsaGp1c3QgPSAwLjcpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSxzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueC50b3AgPSBlbGVtZW50X2JsYW5rKCksYXhpcy50aWNrcy54LnRvcCA9IGVsZW1lbnRfYmxhbmsoKSxheGlzLmxpbmUueC50b3AgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgeWxhYigiR2VuZSBtZXRoeWxhdGlvbiAlIC0gMTEtMTIgaHJzIikgICsgeGxhYihOVUxMKQoKIyB0aWZmKCJFeHBNZXRoeWxfY29yXzEyaHJzLnRpZmYiLCB3aWR0aCA9IDIuNSwgaGVpZ2h0ID0gMy41LCB1bml0cyA9ICJpbiIscmVzID0gMzAwLGNvbXByZXNzaW9uID0gImx6dyIpCiMgRXhwTWV0aHlsX2Nvcl8xMmhycwojIGRldi5vZmYoKQpzdXBwcmVzc1dhcm5pbmdzKGdyaWQuYXJyYW5nZShFeHBNZXRoeWxfY29yXzEyaHJzKSkKYGBgCgpHZW5lIGV4cHJlc3Npb24gYXQgMjAgYW5kIDI0LTYwIGhycyBlbWJyeW9zIGJhc2VkIG9uIG1ldGh5bGF0aW9uIGZyb20gMjQtNjAgaHJzIGVtYnJ5b3MgLSBGaWcgNUksIHJpZ2h0CgpgYGB7ciBmaWc4LCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gMi41fQoKRXhwTWV0aHlsX2Nvcl8yNGhycyA8LSBlbWJyeW9fRXhwX01ldGh5bF9kYXRhICU+JSBzZWxlY3QoLWMoYENwR19OXzlocnNgOmBDcEdfTl8yNGhyc2AsYG1ldGh5bGF0aW9uXzlocnNgLGBtZXRoeWxhdGlvbl8xMmhyc2ApKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYyhnZW5lX2lkLG1ldGh5bGF0aW9uXzI0aHJzKSxuYW1lc190byA9ICJleHBfc3RhZ2UiLHZhbHVlc190bz0iZXhwX2NvdW50IikgJT4lIAogIG11dGF0ZShleHBfc3RhZ2U9ZmFjdG9yKGV4cF9zdGFnZSxsZXZlbHMgPSBjKCJnZW5lX2lkIiwiMC05aHJzIiwiMTFocnMiLCIxMmhycyIsIjE0aHJzIiwiMTZocnMiLCIyMGhycyIsIjI0aHJzIiwiMjQtNjBocnMiKSkpICU+JQogIG11dGF0ZShleHBfY2F0PSBpZmVsc2UoZXhwX2NvdW50ID09IDAsICIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShiZXR3ZWVuKGV4cF9jb3VudCwwLDEpLCLiiaQgMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGJldHdlZW4oZXhwX2NvdW50LDEsNSksIuKJpCA1Iiwi4omlIDUiKSkpKSAlPiUgCiAgZmlsdGVyKGV4cF9zdGFnZSAlaW4lIGMoIjI0aHJzIiwiMjQtNjBocnMiKSkgJT4lCiAgbXV0YXRlKGV4cF9jYXQ9ZmFjdG9yKGV4cF9jYXQsbGV2ZWxzID0gYygiMCIsIuKJpCAxIiwi4omkIDUiLCLiiaUgNSIpKSkgJT4lCiAgZ2dwbG90KGFlcyhmaWxsPWV4cF9zdGFnZSx4PWV4cF9jYXQseT1tZXRoeWxhdGlvbl8yNGhycykpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyID0gImdyZXkiLG91dGxpZXIuc2l6ZSA9IDAuNCxhbHBoYT0wLjYpKyAKICB5bGltKE5BLDIwKSArICMgdG8gcHJpbnQgaW4gbm90ZWJvb2sKICAjc2NhbGVfeV9icmVhayhjKDIwLCA5NSksIHNjYWxlcyA9IDAuMDEsIHRpY2tsYWJlbHM9Yyg5NSwgMTAwKSkgKyAjIHRvIHNhdmUgZmlndXJlCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImZvcmVzdGdyZWVuIiwiZ2FpbnNib3JvIiwiZGFya29yYW5nZTEiKSkgKyAgI3NjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMyksIGNvbG9yPSJjaG9jb2xhdGU0IiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC41KSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDMpLCBjb2xvcj0iY2hvY29sYXRlNCIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuNSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICdjbScpLGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJ0b3AiLGxlZ2VuZC5qdXN0aWZpY2F0aW9uPSJyaWdodCIsbGVnZW5kLm1hcmdpbj1tYXJnaW4oMCwwLDAsMCksI2xlZ2VuZC5ib3gubWFyZ2luPW1hcmdpbigtMjAsLTEwMCwtMTAsLTEwKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsYW5nbGUgPTAsdmp1c3QgPSAwLjY1LGhqdXN0ID0gMC43KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LngudG9wID0gZWxlbWVudF9ibGFuaygpLGF4aXMudGlja3MueC50b3AgPSBlbGVtZW50X2JsYW5rKCksYXhpcy5saW5lLngudG9wID0gZWxlbWVudF9ibGFuaygpKSArIAogIHlsYWIoIkdlbmUgbWV0aHlsYXRpb24gJSAtIDI0LTYwIGhycyIpICsgeGxhYihOVUxMKQoKIyB0aWZmKCJFeHBNZXRoeWxfY29yXzI0aHJzLnRpZmYiLCB3aWR0aCA9IDIuNSwgaGVpZ2h0ID0gMy41LCB1bml0cyA9ICJpbiIscmVzID0gMzAwLGNvbXByZXNzaW9uID0gImx6dyIpCiMgRXhwTWV0aHlsX2Nvcl8yNGhycwojIGRldi5vZmYoKQpzdXBwcmVzc1dhcm5pbmdzKGdyaWQuYXJyYW5nZShFeHBNZXRoeWxfY29yXzI0aHJzKSkKYGBgCiMjIE1ldGh5bGF0aW9uIGZvciBkaWZmZXJlbnQgZGV2ZWxvcG1lbnRhbCBnZW5lIGNhdGVnb3JpZXMgLSBGaWcgNUoKCjExLTEyIGhycyBtZXRoeWxhdGlvbgoKYGBge3IgZmlnOSwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDR9CiMgc2V0d2QoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL3dnYnNfYW5hbHlzaXMvIikKZ2VuZV9jYXRlZ29yaWVzIDwtIHJlYWQudGFibGUoIi9kcml2ZXMvc3NkMS9tYW51ZWwvcGhhdy8yMDIyX2FuYWx5c2lzL216dF9hbmFseXNpcy9kZXZfZ2VuZXNfY2F0ZWdvcmllcy5jc3YiLGhlYWRlciA9IFQsc3RyaW5nc0FzRmFjdG9ycyA9IEYsc2VwPSIsIikKCm15X2NvbXBhcmlzb25zID0gbGlzdChjKCJNaW5vciB3YXZlIGFsbCIsIk1pbm9yIHdhdmUgenlnb3RpYyIpLCBjKCJNYXRlcm5hbCIsIk1pbm9yIHdhdmUgYWxsIiksCiAgICAgICAgICAgICAgICAgICAgICBjKCJNYWpvciB3YXZlIGFsbCIsIk1ham9yIHdhdmUgenlnb3RpYyIpLGMoIk1hdGVybmFsIiwiTWlub3Igd2F2ZSB6eWdvdGljIikpIyxjKCJNYXRlcm5hbCIsIk1ham9yIHdhdmUgenlnb3RpYyIpKQoKWkdBX21ldGh5bGF0aW9uXzEyaCAgPC0gZ2VuZUJvZHlfZnVsbF9tZXRoRGF0YSAlPiUgI3JlcGxhY2UoaXMubmEoLiksIDApICU+JQogIG11dGF0ZShDbGFzcyA9IGlmZWxzZShnZW5lICVpbiUgZ2VuZV9jYXRlZ29yaWVzJHB6X21pbm9yX3dhdmUsIk1pbm9yIHdhdmUgenlnb3RpYyIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVfY2F0ZWdvcmllcyRtaW5vcl93YXZlX2FsbEdlbmVzLCJNaW5vciB3YXZlIGFsbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVfY2F0ZWdvcmllcyRwel9tYWpvcl93YXZlLCJNYWpvciB3YXZlIHp5Z290aWMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVfY2F0ZWdvcmllcyRtYXRlcm5hbF9nZW5lc19ub1pHQSwiTWF0ZXJuYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ2VuZSAlaW4lIGdlbmVfY2F0ZWdvcmllcyRtYWpvcl93YXZlX2FsbEdlbmVzLCJNYWpvciB3YXZlIGFsbCIsInJlc3QiKSkpKSkpICU+JSAKICBtdXRhdGUoQ2xhc3MgPSBmYWN0b3IoQ2xhc3MsbGV2ZWxzID0gYygiTWF0ZXJuYWwiLCJNaW5vciB3YXZlIGFsbCIsIk1pbm9yIHdhdmUgenlnb3RpYyIsIk1ham9yIHdhdmUgYWxsIiwiTWFqb3Igd2F2ZSB6eWdvdGljIikpKSAlPiUKICBmaWx0ZXIoQ2xhc3MgIT0gInJlc3QiLGNsYXNzPT0gIkNvdjEyaHJzIikgJT4lICNncm91cF9ieShDbGFzcykgJT4lIHN1bW1hcmlzZShtZWFuc3M9bWVhbih0eF9sbikpCiAgZ2dwbG90KGFlcyh4PUNsYXNzLCB5PW1ldGh5bGF0aW9uLGZpbGw9Q2xhc3MpLHNpemU9MC4zKSArIGdlb21faml0dGVyKHNpemU9MC4zLCBhbHBoYT0wLjMsY29sb3I9ImdyZXkiKSArIGdlb21fdmlvbGluKGFscGhhPTAuNSkgKyB0aGVtZV9taW5pbWFsKCkgKwogIHlsaW0oTkEsMzApKwogICNzY2FsZV95X2JyZWFrKGMoMzAsIDYwKSwgc2NhbGVzID0gMC4xLCB0aWNrbGFiZWxzPWMoNjAsIDEwMCkpICsjIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDUwKSkgKwogIHhsYWIoTlVMTCkgKyB5bGFiKCJHZW5lIG1ldGh5bGF0aW9uIC0gMTEtMTIgaHJzIikgKwogIHN0YXRfc3VtbWFyeShmdW49bWVkaWFuLCBnZW9tPSJwb2ludCIsIHNoYXBlPTIzLCBzaXplPTEuNSwgY29sb3I9ImJsYWNrIiwgZmlsbD0icmVkIixhbHBoYT0xKSsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSIgIiwgdmFsdWVzPWMoIm5hdnlibHVlIiwgIiMyQjgzQkEiLCAib3JhbmdlIiwiZmlyZWJyaWNrNCIsInNlYWdyZWVuNCIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyMCwgdmp1c3QgPSAwLjksIGhqdXN0PTAuNzUsc2l6ZT0xMCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSxsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgICAgIGF4aXMudGV4dC55LnJpZ2h0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS55LnJpZ2h0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueS5yaWdodCA9IGVsZW1lbnRfYmxhbmsoKSkjICsgc3RhdF9jb21wYXJlX21lYW5zKGNvbXBhcmlzb25zID0gbXlfY29tcGFyaXNvbnMsbGFiZWwgPSAicC5zaWduaWYiLHNpemU9Mi41LHZqdXN0ID0gMCkjICsgc3RhdF9jb21wYXJlX21lYW5zKGxhYmVsLnkgPSA4LCBsYWJlbC54PTEuNSwgc2l6ZT01KSAKI1pHQV9tZXRoeWxhdGlvbl8xMmgKCiMgdGlmZigiWkdBX21ldGh5bGF0aW9uXzEyaC50aWZmIiwgd2lkdGggPSAzLCBoZWlnaHQgPSAzLjUsIHVuaXRzID0gImluIixyZXMgPSA4MDAsY29tcHJlc3Npb24gPSAibHp3IikKIyBaR0FfbWV0aHlsYXRpb25fMTJoCiMgZGV2Lm9mZigpCnN1cHByZXNzV2FybmluZ3MoZ3JpZC5hcnJhbmdlKFpHQV9tZXRoeWxhdGlvbl8xMmgpKQoKYGBgCjI0LTYwIGhycyBtZXRoeWxhdGlvbgoKYGBge3IgZmlnMTAsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA0fQpaR0FfbWV0aHlsYXRpb25fMjRfNjBoICA8LSBnZW5lQm9keV9mdWxsX21ldGhEYXRhICU+JSAjcmVwbGFjZShpcy5uYSguKSwgMCkgJT4lCiAgbXV0YXRlKENsYXNzID0gaWZlbHNlKGdlbmUgJWluJSBnZW5lX2NhdGVnb3JpZXMkcHpfbWlub3Jfd2F2ZSwiTWlub3Igd2F2ZSB6eWdvdGljIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZV9jYXRlZ29yaWVzJG1pbm9yX3dhdmVfYWxsR2VuZXMsIk1pbm9yIHdhdmUgYWxsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZV9jYXRlZ29yaWVzJHB6X21ham9yX3dhdmUsIk1ham9yIHdhdmUgenlnb3RpYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZV9jYXRlZ29yaWVzJG1hdGVybmFsX2dlbmVzX25vWkdBLCJNYXRlcm5hbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShnZW5lICVpbiUgZ2VuZV9jYXRlZ29yaWVzJG1ham9yX3dhdmVfYWxsR2VuZXMsIk1ham9yIHdhdmUgYWxsIiwicmVzdCIpKSkpKSkgJT4lIAogIG11dGF0ZShDbGFzcyA9IGZhY3RvcihDbGFzcyxsZXZlbHMgPSBjKCJNYXRlcm5hbCIsIk1pbm9yIHdhdmUgYWxsIiwiTWlub3Igd2F2ZSB6eWdvdGljIiwiTWFqb3Igd2F2ZSBhbGwiLCJNYWpvciB3YXZlIHp5Z290aWMiKSkpICU+JQogIGZpbHRlcihDbGFzcyAhPSAicmVzdCIsY2xhc3M9PSAiQ292MjRocnMiKSAlPiUgI2dyb3VwX2J5KENsYXNzKSAlPiUgc3VtbWFyaXNlKG1lYW5zcz1tZWFuKHR4X2xuKSkKICBnZ3Bsb3QoYWVzKHg9Q2xhc3MsIHk9bWV0aHlsYXRpb24sZmlsbD1DbGFzcyksc2l6ZT0wLjMpICsgZ2VvbV9qaXR0ZXIoc2l6ZT0wLjMsIGFscGhhPTAuMyxjb2xvcj0iZ3JleSIpICsgZ2VvbV92aW9saW4oYWxwaGE9MC41KSArIHRoZW1lX21pbmltYWwoKSArCiAgeWxpbShOQSwzMCkrCiAgI3NjYWxlX3lfYnJlYWsoYygzMCwgNjApLCBzY2FsZXMgPSAwLjEsIHRpY2tsYWJlbHM9Yyg2MCwgMTAwKSkgKyMgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgNTApKSArCiAgeGxhYihOVUxMKSArIHlsYWIoIkdlbmUgbWV0aHlsYXRpb24gLSAyNC02MCBocnMiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bj1tZWRpYW4sIGdlb209InBvaW50Iiwgc2hhcGU9MjMsIHNpemU9MS41LCBjb2xvcj0iYmxhY2siLCBmaWxsPSJyZWQiLGFscGhhPTEpKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IiAiLCB2YWx1ZXM9YygibmF2eWJsdWUiLCAiIzJCODNCQSIsICJvcmFuZ2UiLCJmaXJlYnJpY2s0Iiwic2VhZ3JlZW40IikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDIwLCB2anVzdCA9IDAuOSwgaGp1c3Q9MC43NSxzaXplPTEwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTgpLCBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICAgICAgYXhpcy50ZXh0LnkucmlnaHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLnkucmlnaHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55LnJpZ2h0ID0gZWxlbWVudF9ibGFuaygpKSMgKyBzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucyxsYWJlbCA9ICJwLnNpZ25pZiIsc2l6ZT0yLjUsdmp1c3QgPSAwKSMgKyBzdGF0X2NvbXBhcmVfbWVhbnMobGFiZWwueSA9IDgsIGxhYmVsLng9MS41LCBzaXplPTUpIAoKc3VwcHJlc3NXYXJuaW5ncyhncmlkLmFycmFuZ2UoWkdBX21ldGh5bGF0aW9uXzI0XzYwaCkpCmBgYAoK